From patchwork Mon May 16 14:10:09 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 15907 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 7DFDDC3256 for ; Mon, 16 May 2022 14:10:52 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 737BC6565A; Mon, 16 May 2022 16:10:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1652710250; bh=TM9wLK6War1E/T35ufvdD/72QP07S13uSskcfJQFlXo=; 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=YW9PFlIqo19jZxLSY/0we2aU+s6zwFBeyDH6lks0sOMxnABwStpyLx6oTLtmdgSo/ kIM5l1A93oOz1HK2o6TwUvXezysNw4pvh9C3AjhvaGxEZ+25b4u+zjuz2H4w3QZ++S y8btyGinGA0jY9gBBZwbdkMrObTF27hv18zNIK19ekDoIu4pqSR1IpMV+E7DqsGqq1 uFxb1YW7GLfjpayU6bIdEsRzBM5sEiIws8yNNpBWwp8/88rNFerHKSHuVrVG8GbUBa 6fgMGsb3AWpwh4qMx+0pEaFpVcmcV76O34rRkYvuVVASTpLlYZ9p15RFmecxq4VXPk OKHDGcGkfEXDQ== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8F42261FB8 for ; Mon, 16 May 2022 16:10:48 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="whiwaG15"; dkim-atps=neutral Received: from deskari.lan (91-156-85-209.elisa-laajakaista.fi [91.156.85.209]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 9A51848F; Mon, 16 May 2022 16:10:47 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1652710248; bh=TM9wLK6War1E/T35ufvdD/72QP07S13uSskcfJQFlXo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=whiwaG15PwJWE9+QEPfHVesCz89qOsrJ8T6jCXYV2R5OyvyyDKdJ/weu9arKk+bUj ykQwxJVxH034BqxnBb1YHaahwkNCwgriRZ/SYCbKbhkIfWetoLnVndU0YkVGP7Vqz9 0jwbGqlGOcd8ozHc3i+rLvYMFFnzCN8jtOb9jvv0= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Mon, 16 May 2022 17:10:09 +0300 Message-Id: <20220516141022.96327-2-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> References: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 01/14] py: meson: fix comment about stubs 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: Tomi Valkeinen via libcamera-devel From: Tomi Valkeinen Reply-To: Tomi Valkeinen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" At least pyright seems to be able to use the stubs from the libcamera-stubs directory, so no need to copy the generated files. Adjust the comment accordingly. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- src/py/libcamera/meson.build | 1 - 1 file changed, 1 deletion(-) diff --git a/src/py/libcamera/meson.build b/src/py/libcamera/meson.build index 0cd7c75b..38f619d0 100644 --- a/src/py/libcamera/meson.build +++ b/src/py/libcamera/meson.build @@ -63,4 +63,3 @@ install_data(['__init__.py'], install_dir : destdir) # \todo Generate stubs when building. See https://peps.python.org/pep-0484/#stub-files # Note: Depends on pybind11-stubgen. To generate pylibcamera stubs: # $ PYTHONPATH=build/src/py pybind11-stubgen --no-setup-py -o build/src/py libcamera -# $ mv build/src/py/libcamera-stubs/* build/src/py/libcamera/ From patchwork Mon May 16 14:10:10 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 15908 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 3165EC326C for ; Mon, 16 May 2022 14:10:54 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D6F3D65664; Mon, 16 May 2022 16:10:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1652710250; bh=MbwnSfF0sSwNjlsdM6Fc3w1mndHsQnPSB9jGgx82smk=; 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=zPRrUsFmYQMfQPotliXjiQZipGPYC1ZPjxrWQ5fr/4GcPF/oF7UPvki3WjoWOFN51 rWyyuKJdCpCOij5sxLouhdGk8+bZBiPt6CtBc5q20UAnViAGsoGPeztKday5F4cKp/ DayqQsTlWXGUkZ8GRDBWdARxQVW02ddVlpPIujgiUblBiEVBSNjdt+DxqVbzRxPItH 1R7V/rq5PLex9yf52JMBxpV9qluNIgOFooMzp79BXgAYuD7hWjhhTuGOIaPxWGs87A 4oVwSlYTp0x0dmaWBhZlQEK56SRm9lVw5RnwchJ0yHc+OBWB6vU95kx2Zhsh8FP/t/ 9/Ngjp1Q4H3Qg== 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 BC78965654 for ; Mon, 16 May 2022 16:10:48 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="N2kJTiOM"; dkim-atps=neutral Received: from deskari.lan (91-156-85-209.elisa-laajakaista.fi [91.156.85.209]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 30A9E563; Mon, 16 May 2022 16:10:48 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1652710248; bh=MbwnSfF0sSwNjlsdM6Fc3w1mndHsQnPSB9jGgx82smk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=N2kJTiOMHkDPohc/0y461NZScHdfeSNKIjhCsVx+8+JArJxAC8Yr/cwfI7hrSb46m MV9eWHbUWuZAcFvAhWn/2K7yyH6ZsPvMYxCfPxsIG09+xt9zu3c6zOk26AuJcx9qUP rHwq9Vgb3bR+FoONSuvNgM+Yx2GGLz/jCGOPfXh4= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Mon, 16 May 2022 17:10:10 +0300 Message-Id: <20220516141022.96327-3-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> References: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 02/14] py: meson: add pystubs build target 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: Tomi Valkeinen via libcamera-devel From: Tomi Valkeinen Reply-To: Tomi Valkeinen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add a 'pystubs' build target for building the python stubs. For now this needs to be ran manually. I didn't figure out how to generate the stubs after the libcamera bindings are built. Signed-off-by: Tomi Valkeinen --- src/py/libcamera/meson.build | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/py/libcamera/meson.build b/src/py/libcamera/meson.build index 38f619d0..fbd33139 100644 --- a/src/py/libcamera/meson.build +++ b/src/py/libcamera/meson.build @@ -60,6 +60,18 @@ run_command('ln', '-fsT', '../../../../src/py/libcamera/__init__.py', install_data(['__init__.py'], install_dir : destdir) -# \todo Generate stubs when building. See https://peps.python.org/pep-0484/#stub-files +# \todo Generate stubs when building, and install them. +# See https://peps.python.org/pep-0484/#stub-files # Note: Depends on pybind11-stubgen. To generate pylibcamera stubs: # $ PYTHONPATH=build/src/py pybind11-stubgen --no-setup-py -o build/src/py libcamera +# The target below can be ran manually, but how to create a meson target that +# is run if pycamera is built? + +stubgen = find_program('pybind11-stubgen', required : false) + +if stubgen.found() + run_target('pystubs', + depends: pycamera, + env: {'PYTHONPATH': meson.project_build_root() / 'src/py'}, + command : [stubgen, '--no-setup-py', '-o', meson.project_build_root() / 'src/py', 'libcamera']) +endif From patchwork Mon May 16 14:10:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 15909 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 2FFB4C3256 for ; Mon, 16 May 2022 14:10:55 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7C7026566D; Mon, 16 May 2022 16:10:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1652710254; bh=8WhmL1Q7/2UkeuDtkTsfW1FkL/8USIayjSt1ZXA2eko=; 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=uz60YJcWmeOf6BVk5/fwRa53dXvC5mo5cOJ/+HiWESXvH16WNB0AWWOwrlcLoAAl6 n+3wZMcMRIy65Z/9Cjk+ydgVm0vfAGUy9il88PMXjF/e9dfeI9WD9haZs/wFbyXIUC GLfTZ3bUQArWZCIJceMdK2VPVOPEil+Nf63uq2KtI6+qO0K7YjpIkkinExAc5XwZ6F OVdd+SVpNU1fm8AfhFaKTIqNIdu3jxn7XIxiRdTqkoLl2U5eQT8dP9j0Ia7I2HJaii b2aFxw4rERv2hDwg8gMcc4k7Dd7tG72h6fh2gx918GVLizOvlyGhPU6Li5gzLpL509 DymJiiiH6eMtQ== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 547EF6565D for ; Mon, 16 May 2022 16:10:49 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="NCwN8aXA"; dkim-atps=neutral Received: from deskari.lan (91-156-85-209.elisa-laajakaista.fi [91.156.85.209]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B1461576; Mon, 16 May 2022 16:10:48 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1652710249; bh=8WhmL1Q7/2UkeuDtkTsfW1FkL/8USIayjSt1ZXA2eko=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=NCwN8aXAR4ptWsQvQ9Apgb9KiNnJhADMCixiv5773PByCI1ieNm2n3T0sC17jjFO3 zva9NjjcbBCWHvxcp0goe7dodeAGDuHRMvHJFxn/XxtPrM/5KOng/RwoGaLo/E/sFE Zv/y8jnQJwMweWOoxXNo2eQZPlnNM4P0rTD4qRaE= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Mon, 16 May 2022 17:10:11 +0300 Message-Id: <20220516141022.96327-4-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> References: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 03/14] py: pymain: fix indent 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: Tomi Valkeinen via libcamera-devel From: Tomi Valkeinen Reply-To: Tomi Valkeinen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Fix two minor mis-indents. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- src/py/libcamera/pymain.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/py/libcamera/pymain.cpp b/src/py/libcamera/pymain.cpp index fb89975c..af22205e 100644 --- a/src/py/libcamera/pymain.cpp +++ b/src/py/libcamera/pymain.cpp @@ -394,7 +394,7 @@ PYBIND11_MODULE(_libcamera, m) pyStreamConfiguration .def("__str__", &StreamConfiguration::toString) .def_property_readonly("stream", &StreamConfiguration::stream, - py::return_value_policy::reference_internal) + py::return_value_policy::reference_internal) .def_property( "size", [](StreamConfiguration &self) { @@ -416,7 +416,7 @@ PYBIND11_MODULE(_libcamera, m) .def_readwrite("frame_size", &StreamConfiguration::frameSize) .def_readwrite("buffer_count", &StreamConfiguration::bufferCount) .def_property_readonly("formats", &StreamConfiguration::formats, - py::return_value_policy::reference_internal) + py::return_value_policy::reference_internal) .def_readwrite("color_space", &StreamConfiguration::colorSpace); pyStreamFormats From patchwork Mon May 16 14:10:12 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 15910 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 3CAF0C326C for ; Mon, 16 May 2022 14:10:56 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8FF796566B; Mon, 16 May 2022 16:10:55 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1652710255; bh=o2UDMjgVn8X2IEOwsdsfRezjLPYp3RRR5wcuF29R+tQ=; 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=EjShfc5ppFmJbnKThM4ndl7h1WgSJG80fBg6Hj6r4djEZeqts/743CmaguEtSHPCw +9qOLjBcWAO/teJl/3fsF25lUMhgrh0PgL9G+8Ssiz/UV51G9ti6rxkOTjERPF7sm/ 3U6J5MKSQ+hHYMTV7t2zXuHIRDAZlKHUIqbBRA37Y87Lt0FdsXrvtv6abzxgLJ+QYO oPudYsjP6C17SjxIjaRismqzOw6tDCnGRoBUjg5Q/zZuBz7+AqckHs0pxr7jgBaYme n36U9vh3+HzfTbN6GJNqpiJ6ZtWfhLPiOhHWCyQNkp13Tza5R2IhAIwQTI929UfLaq /mRPTj82j3nQg== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C6E3B61FB8 for ; Mon, 16 May 2022 16:10:49 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="QrNIjQ7+"; dkim-atps=neutral Received: from deskari.lan (91-156-85-209.elisa-laajakaista.fi [91.156.85.209]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 3A1F659D; Mon, 16 May 2022 16:10:49 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1652710249; bh=o2UDMjgVn8X2IEOwsdsfRezjLPYp3RRR5wcuF29R+tQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=QrNIjQ7+QEiCsCWspbKL44ZXl53XE0Qo8YbLQ/N6qxvVZqWLZSpxKFf1VfeepEViG 2nhpdXWrtajkbV4LdD7M8pRT40GjYqtg7vNruHGgfdxDcNUI4r72CErVoGw1afgQ38 I0YFyBWjBcgSf76d47qDSWBgC1197vVJUFyILaHo= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Mon, 16 May 2022 17:10:12 +0300 Message-Id: <20220516141022.96327-5-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> References: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 04/14] py: unittests: fix selector fd use 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: Tomi Valkeinen via libcamera-devel From: Tomi Valkeinen Reply-To: Tomi Valkeinen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" pyright complains about passing fileobj to os.read. Indeed, the parameter should be an int, but I guess fileobj gets automatically converted. In any case, using the fd is better. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- test/py/unittests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/py/unittests.py b/test/py/unittests.py index cbc00ff3..9326358d 100755 --- a/test/py/unittests.py +++ b/test/py/unittests.py @@ -262,8 +262,8 @@ class SimpleCaptureMethods(CameraTesterBase): running = True while running: events = sel.select() - for key, mask in events: - os.read(key.fileobj, 8) + for key, _ in events: + os.read(key.fd, 8) ready_reqs = cm.get_ready_requests() From patchwork Mon May 16 14:10:13 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 15911 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 18A82C3256 for ; Mon, 16 May 2022 14:10:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 246D965674; Mon, 16 May 2022 16:10:56 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1652710256; bh=/DzF7lrgxQNz4Pc5b7ZShv+ZljvReYGaRty30lW76/I=; 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=DSTYWiNU+znSmeyS6YNlPy8lEbHOYYZL8V61cPC1XE351HW+yCzUtJIaVmUjsKktP 2Zebi8AcWSlaQvW2COhmsFa5lOdf49izTFueOHqjj66QK5kOWVrKjogcOimk6CrQ38 /zrGzHU2sQTLdqD5TVme8LxH7ic8MRHTVNja9KZtjY9B9H99adwFCxD3EcklZY4XQu XFc71jElwoqR/cprY2zPbiOtSlwvCiln6AYnh/obTv2+wdRE9v41UXizkIlAyPUAdM +RF8TRBJqXHIfIe9/wdG3X8X7CETPJGJxm/Ue+Z3zF9IVyrWgpTRnK7uOZssB0hU9X RwRQAt7W9d9jQ== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5292565653 for ; Mon, 16 May 2022 16:10:50 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Q7dpeuo/"; dkim-atps=neutral Received: from deskari.lan (91-156-85-209.elisa-laajakaista.fi [91.156.85.209]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BB4AB898; Mon, 16 May 2022 16:10:49 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1652710250; bh=/DzF7lrgxQNz4Pc5b7ZShv+ZljvReYGaRty30lW76/I=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Q7dpeuo/VYMgIDylc7Ail91h0J3v2Ime0luPv/FOFENKIVAAYcdpCf9AptFclnLam shzmBP11yUIMceQtgLq6NfBKDbnpNjQwogYmowh6UKjOYrLSo5+29mfx6kdv23WFcv 5tp5aguNd/dhNmsTNS1qkRwygMT1tiQhW69Cd45I= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Mon, 16 May 2022 17:10:13 +0300 Message-Id: <20220516141022.96327-6-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> References: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 05/14] py: unittests: verify that cam and cm are freed 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: Tomi Valkeinen via libcamera-devel From: Tomi Valkeinen Reply-To: Tomi Valkeinen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add checks to CameraTesterBase to verify that both the Camera and the CameraManager gets freed. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- test/py/unittests.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/py/unittests.py b/test/py/unittests.py index 9326358d..288dcd48 100755 --- a/test/py/unittests.py +++ b/test/py/unittests.py @@ -83,6 +83,10 @@ class CameraTesterBase(BaseTestCase): self.cm = None raise Exception('Failed to acquire camera') + self.wr_cam = weakref.ref(self.cam) + self.wr_cm = weakref.ref(self.cm) + + def tearDown(self): # If a test fails, the camera may be in running state. So always stop. self.cam.stop() @@ -94,6 +98,9 @@ class CameraTesterBase(BaseTestCase): self.cam = None self.cm = None + self.assertIsNone(self.wr_cm()) + self.assertIsNone(self.wr_cam()) + class AllocatorTestMethods(CameraTesterBase): def test_allocator(self): From patchwork Mon May 16 14:10:14 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 15912 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 F16B7C326D for ; Mon, 16 May 2022 14:10:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D31CF6566C; Mon, 16 May 2022 16:10:56 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1652710256; bh=0K2ROD8e2fMSSZhVgjcTx+alQj+rvakcSDAIWLV9tJ0=; 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=T6TNvMj9HRpei4ti2I1q4buoIb1X0YkhwyasSuRbb5tvCRRLHcA89f1QzdBbmOcqC V2LiVknUeTCYmsUWXMFf04YWampZIpTuIrksaLJND4lcUKXI5L+4yzqsIn8owH6FLI Vy9CBiL4HVLDU7itnQ3xWG8pe8pAxXOGB7rbIbcSjz6dlM9AwAJX8Hlnj1iC0rfcXM 0RWFMxtun6o+9Y+RijoC8QIj1pmQgGbF3OMwWHFQn5+OQY5idzXzhn5RaNCHlW4iDC Y5ctnYM7GYqAEqvZfBfqZ6XZMQle2nGAbo158Cy3hsPot31DUoewWALFcVWRcI4Srl olX7BOPssHEJg== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id F051865665 for ; Mon, 16 May 2022 16:10:50 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="iy/V0Ij6"; dkim-atps=neutral Received: from deskari.lan (91-156-85-209.elisa-laajakaista.fi [91.156.85.209]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 5BB6A48F; Mon, 16 May 2022 16:10:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1652710250; bh=0K2ROD8e2fMSSZhVgjcTx+alQj+rvakcSDAIWLV9tJ0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=iy/V0Ij6WeQdV7LYiRfLF+cE3wvv+KKVS6Ic0zIVEAr+AdWSdUWMpl4y7gkeIvk5e 2/2Vs5DxJNbVFpyzvGIYUXo38SIXufGh4KT7/zGfs1Ts6dV8PApOTSSMkIaA4a4I8S 4IzC55bDUUepCPzlkE7q1ae52vskFoHi8PXvj/VM= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Mon, 16 May 2022 17:10:14 +0300 Message-Id: <20220516141022.96327-7-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> References: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 06/14] py: unittests: make typechecker happy 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: Tomi Valkeinen via libcamera-devel From: Tomi Valkeinen Reply-To: Tomi Valkeinen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add some annotations to reduce the typechecker warnings. Signed-off-by: Tomi Valkeinen --- test/py/unittests.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/test/py/unittests.py b/test/py/unittests.py index 288dcd48..e5591f3f 100755 --- a/test/py/unittests.py +++ b/test/py/unittests.py @@ -10,6 +10,7 @@ import libcamera as libcam import os import selectors import time +import typing import unittest import weakref @@ -70,6 +71,9 @@ class SimpleTestMethods(BaseTestCase): class CameraTesterBase(BaseTestCase): + cm: typing.Any + cam: typing.Any + def setUp(self): self.cm = libcam.CameraManager.singleton() self.cam = next((cam for cam in self.cm.cameras if 'platform/vimc' in cam.id), None) @@ -131,8 +135,8 @@ class AllocatorTestMethods(CameraTesterBase): self.assertTrue(ret > 0) wr_allocator = weakref.ref(allocator) - buffers = allocator.buffers(stream) - buffers = None + buffers = allocator.buffers(stream) # type: ignore + buffers = None # type: ignore buffer = allocator.buffers(stream)[0] self.assertIsNotNone(buffer) @@ -166,7 +170,8 @@ class SimpleCaptureMethods(CameraTesterBase): self.assertTrue(camconfig.size == 1) streamconfig = camconfig.at(0) - fmts = streamconfig.formats + fmts = streamconfig.formats # type: ignore + fmts = None # type: ignore ret = cam.configure(camconfig) self.assertZero(ret) @@ -225,7 +230,7 @@ class SimpleCaptureMethods(CameraTesterBase): self.assertTrue(camconfig.size == 1) streamconfig = camconfig.at(0) - fmts = streamconfig.formats + fmts = streamconfig.formats # type: ignore ret = cam.configure(camconfig) self.assertZero(ret) @@ -349,9 +354,9 @@ if __name__ == '__main__': gc.unfreeze() gc.collect() - obs_after = get_all_objects([obs_before]) + obs_after = get_all_objects([obs_before]) # type: ignore - before = create_type_count_map(obs_before) + before = create_type_count_map(obs_before) # type: ignore after = create_type_count_map(obs_after) leaks = diff_type_count_maps(before, after) From patchwork Mon May 16 14:10:15 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 15913 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 A445EC326E for ; Mon, 16 May 2022 14:10:58 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D243065672; Mon, 16 May 2022 16:10:57 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1652710257; bh=PnHyInzBKWeLdu4GkQm2Sbu5jWaEQC26GxZMioyOato=; 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=b4fzGUI8Ya9kKZ8LKCESsQombsWZte2uMlR+ke6hfPr9SWJ51dZHYA+w0GkQU+fZC K5mWkvkEyIK2WcCaxQjmxWnnEFU5unYZr6eINZH6dHBo1a4BXioQ0Zk9Mcn4fOOGsn QhQNddM0McMoUSBHwOKcAOkk7WcrJGJU2D/6gLevWV5zp4Zqyr47Rc8bQrgpo1Xixg 50VT7/LsSz4THAmsPqmYSujHAb8T1bo6U1DAv/g65fBpp1ofR2c2C1yVCLgfqQGSjr 9g/P8mGyRiykeh8RD6HCRDUADDGxwNqVKdfyDTPTebTZjPpXIvTMkO7+0zf/en+NRT qy3JRi540v16Q== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 731496565C for ; Mon, 16 May 2022 16:10:51 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="XvePJBxT"; dkim-atps=neutral Received: from deskari.lan (91-156-85-209.elisa-laajakaista.fi [91.156.85.209]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id DBF2A484; Mon, 16 May 2022 16:10:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1652710251; bh=PnHyInzBKWeLdu4GkQm2Sbu5jWaEQC26GxZMioyOato=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XvePJBxT/5Iv/6IskRsJhB722UnJtPTLndUSzATnWVK3e6cT3oemOdjLRs9WYFtPA AWQpMxUUbH5eiVYdw1u1e89X8fDT0TCTfQCt77lxBBoW/QrBxiD3TET0AgOhvkMvY7 juNr2o95HYk0CwOgzmu16vGbM0usv5iyL1wCeUQQ= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Mon, 16 May 2022 17:10:15 +0300 Message-Id: <20220516141022.96327-8-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> References: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 07/14] py: cam.py: exit on exception 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: Tomi Valkeinen via libcamera-devel From: Tomi Valkeinen Reply-To: Tomi Valkeinen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Catch exceptions in the event_handler, as they would get ignored otherwise. Print the exception and return False so that the main loop exits. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- src/py/cam/cam.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/py/cam/cam.py b/src/py/cam/cam.py index 012b191c..c7da97d7 100755 --- a/src/py/cam/cam.py +++ b/src/py/cam/cam.py @@ -11,6 +11,7 @@ import binascii import libcamera as libcam import os import sys +import traceback class CustomAction(argparse.Action): @@ -286,19 +287,23 @@ def capture_start(contexts): # Called from renderer when there is a libcamera event def event_handler(state): - cm = state['cm'] - contexts = state['contexts'] + try: + cm = state['cm'] + contexts = state['contexts'] - os.read(cm.efd, 8) + os.read(cm.efd, 8) - reqs = cm.get_ready_requests() + reqs = cm.get_ready_requests() - for req in reqs: - ctx = next(ctx for ctx in contexts if ctx['idx'] == req.cookie) - request_handler(state, ctx, req) + for req in reqs: + ctx = next(ctx for ctx in contexts if ctx['idx'] == req.cookie) + request_handler(state, ctx, req) - running = any(ctx['reqs-completed'] < ctx['opt-capture'] for ctx in contexts) - return running + running = any(ctx['reqs-completed'] < ctx['opt-capture'] for ctx in contexts) + return running + except Exception as e: + traceback.print_exc() + return False def request_handler(state, ctx, req): From patchwork Mon May 16 14:10:16 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 15914 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 BD17EC3256 for ; Mon, 16 May 2022 14:11:00 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6959C65682; Mon, 16 May 2022 16:11:00 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1652710260; bh=wMmphrOaD0hpFNdcY8kGUJbvzPlXmXi/e5RnIjxNttM=; 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=qUa2NjDRN74fGY/f1pS9vROXDUJkj/R5OsxIEItP2V6E+5Sw2mwoownWml22tWxLA Q2zhzn0sAa3dM+xFyQgRgDf1BO3rfrgBQnW04h5zDLsOsZTCpqW57LeF5ePXGeTQf8 LQgrj0yWII5GlSuW1sojuoLW96QQjLRNOHfH+G/yp5T0EfZuNxdxbfvXJ4il7OYJeA z+IR2ZLdu+IM6BDjokk0yaBdsFZNj2QIREMGjcOijqFZrRK/5KbEWi0ynzD/O6deA6 Os7x05XI5WpAQXEqNQObr8Lw/IYSewiMTt5Aail+UyigzLpuCciIOKHQ2nrwGjIjwy s+mjpeyHlcYPw== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0A2D265654 for ; Mon, 16 May 2022 16:10:52 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="VGbhxW0i"; dkim-atps=neutral Received: from deskari.lan (91-156-85-209.elisa-laajakaista.fi [91.156.85.209]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 68F8F576; Mon, 16 May 2022 16:10:51 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1652710251; bh=wMmphrOaD0hpFNdcY8kGUJbvzPlXmXi/e5RnIjxNttM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VGbhxW0iy4zt20bj2ekxIA6VnIXiYujAdMGhSr4WJUad/9KS6C2fJdpJOUXI0XwTy /WkimP8LuJ6N/xHZjoZfV3+veDOzo3PL23jhrkH1lmtxBQhLvs2256f7XShaHtr67w 0Lhw4ta409D4ih+rD9YNIxszlPC/M/HFjFACEFzY= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Mon, 16 May 2022 17:10:16 +0300 Message-Id: <20220516141022.96327-9-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> References: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 08/14] py: move conversion funcs to libcamera.utils 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: Tomi Valkeinen via libcamera-devel From: Tomi Valkeinen Reply-To: Tomi Valkeinen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" cam_qt.py has a bunch of utility functions for pixel format conversions. Create a new libcamera submodule for these. Also create a symlink from the build dir to the source dir for those new submodule, so that we can run the bindings directly from the build dir. Signed-off-by: Tomi Valkeinen --- src/py/cam/cam_qt.py | 195 +----------------- src/py/libcamera/meson.build | 6 + src/py/libcamera/utils/__init__.py | 4 + .../cam_qt.py => libcamera/utils/conv.py} | 164 +-------------- 4 files changed, 17 insertions(+), 352 deletions(-) create mode 100644 src/py/libcamera/utils/__init__.py copy src/py/{cam/cam_qt.py => libcamera/utils/conv.py} (58%) diff --git a/src/py/cam/cam_qt.py b/src/py/cam/cam_qt.py index 5753f0b2..dc5219eb 100644 --- a/src/py/cam/cam_qt.py +++ b/src/py/cam/cam_qt.py @@ -1,17 +1,13 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2022, Tomi Valkeinen -# -# Debayering code from PiCamera documentation from io import BytesIO -from numpy.lib.stride_tricks import as_strided from PIL import Image from PIL.ImageQt import ImageQt from PyQt5 import QtCore, QtGui, QtWidgets -import numpy as np +import libcamera.utils as camutils import sys - def rgb_to_pix(rgb): img = Image.frombuffer('RGB', (rgb.shape[1], rgb.shape[0]), rgb) qim = ImageQt(img).copy() @@ -19,192 +15,6 @@ def rgb_to_pix(rgb): return pix -def separate_components(data, r0, g0, g1, b0): - # Now to split the data up into its red, green, and blue components. The - # Bayer pattern of the OV5647 sensor is BGGR. In other words the first - # row contains alternating green/blue elements, the second row contains - # alternating red/green elements, and so on as illustrated below: - # - # GBGBGBGBGBGBGB - # RGRGRGRGRGRGRG - # GBGBGBGBGBGBGB - # RGRGRGRGRGRGRG - # - # Please note that if you use vflip or hflip to change the orientation - # of the capture, you must flip the Bayer pattern accordingly - - rgb = np.zeros(data.shape + (3,), dtype=data.dtype) - rgb[r0[1]::2, r0[0]::2, 0] = data[r0[1]::2, r0[0]::2] # Red - rgb[g0[1]::2, g0[0]::2, 1] = data[g0[1]::2, g0[0]::2] # Green - rgb[g1[1]::2, g1[0]::2, 1] = data[g1[1]::2, g1[0]::2] # Green - rgb[b0[1]::2, b0[0]::2, 2] = data[b0[1]::2, b0[0]::2] # Blue - - return rgb - - -def demosaic(rgb, r0, g0, g1, b0): - # At this point we now have the raw Bayer data with the correct values - # and colors but the data still requires de-mosaicing and - # post-processing. If you wish to do this yourself, end the script here! - # - # Below we present a fairly naive de-mosaic method that simply - # calculates the weighted average of a pixel based on the pixels - # surrounding it. The weighting is provided b0[1] a b0[1]te representation of - # the Bayer filter which we construct first: - - bayer = np.zeros(rgb.shape, dtype=np.uint8) - bayer[r0[1]::2, r0[0]::2, 0] = 1 # Red - bayer[g0[1]::2, g0[0]::2, 1] = 1 # Green - bayer[g1[1]::2, g1[0]::2, 1] = 1 # Green - bayer[b0[1]::2, b0[0]::2, 2] = 1 # Blue - - # Allocate an array to hold our output with the same shape as the input - # data. After this we define the size of window that will be used to - # calculate each weighted average (3x3). Then we pad out the rgb and - # bayer arrays, adding blank pixels at their edges to compensate for the - # size of the window when calculating averages for edge pixels. - - output = np.empty(rgb.shape, dtype=rgb.dtype) - window = (3, 3) - borders = (window[0] - 1, window[1] - 1) - border = (borders[0] // 2, borders[1] // 2) - - # rgb_pad = np.zeros(( - # rgb.shape[0] + borders[0], - # rgb.shape[1] + borders[1], - # rgb.shape[2]), dtype=rgb.dtype) - # rgb_pad[ - # border[0]:rgb_pad.shape[0] - border[0], - # border[1]:rgb_pad.shape[1] - border[1], - # :] = rgb - # rgb = rgb_pad - # - # bayer_pad = np.zeros(( - # bayer.shape[0] + borders[0], - # bayer.shape[1] + borders[1], - # bayer.shape[2]), dtype=bayer.dtype) - # bayer_pad[ - # border[0]:bayer_pad.shape[0] - border[0], - # border[1]:bayer_pad.shape[1] - border[1], - # :] = bayer - # bayer = bayer_pad - - # In numpy >=1.7.0 just use np.pad (version in Raspbian is 1.6.2 at the - # time of writing...) - # - rgb = np.pad(rgb, [ - (border[0], border[0]), - (border[1], border[1]), - (0, 0), - ], 'constant') - bayer = np.pad(bayer, [ - (border[0], border[0]), - (border[1], border[1]), - (0, 0), - ], 'constant') - - # For each plane in the RGB data, we use a nifty numpy trick - # (as_strided) to construct a view over the plane of 3x3 matrices. We do - # the same for the bayer array, then use Einstein summation on each - # (np.sum is simpler, but copies the data so it's slower), and divide - # the results to get our weighted average: - - for plane in range(3): - p = rgb[..., plane] - b = bayer[..., plane] - pview = as_strided(p, shape=( - p.shape[0] - borders[0], - p.shape[1] - borders[1]) + window, strides=p.strides * 2) - bview = as_strided(b, shape=( - b.shape[0] - borders[0], - b.shape[1] - borders[1]) + window, strides=b.strides * 2) - psum = np.einsum('ijkl->ij', pview) - bsum = np.einsum('ijkl->ij', bview) - output[..., plane] = psum // bsum - - return output - - -def to_rgb(fmt, size, data): - w = size[0] - h = size[1] - - if fmt == 'YUYV': - # YUV422 - yuyv = data.reshape((h, w // 2 * 4)) - - # YUV444 - yuv = np.empty((h, w, 3), dtype=np.uint8) - yuv[:, :, 0] = yuyv[:, 0::2] # Y - yuv[:, :, 1] = yuyv[:, 1::4].repeat(2, axis=1) # U - yuv[:, :, 2] = yuyv[:, 3::4].repeat(2, axis=1) # V - - m = np.array([ - [1.0, 1.0, 1.0], - [-0.000007154783816076815, -0.3441331386566162, 1.7720025777816772], - [1.4019975662231445, -0.7141380310058594, 0.00001542569043522235] - ]) - - rgb = np.dot(yuv, m) - rgb[:, :, 0] -= 179.45477266423404 - rgb[:, :, 1] += 135.45870971679688 - rgb[:, :, 2] -= 226.8183044444304 - rgb = rgb.astype(np.uint8) - - elif fmt == 'RGB888': - rgb = data.reshape((h, w, 3)) - rgb[:, :, [0, 1, 2]] = rgb[:, :, [2, 1, 0]] - - elif fmt == 'BGR888': - rgb = data.reshape((h, w, 3)) - - elif fmt in ['ARGB8888', 'XRGB8888']: - rgb = data.reshape((h, w, 4)) - rgb = np.flip(rgb, axis=2) - # drop alpha component - rgb = np.delete(rgb, np.s_[0::4], axis=2) - - elif fmt.startswith('S'): - bayer_pattern = fmt[1:5] - bitspp = int(fmt[5:]) - - # TODO: shifting leaves the lowest bits 0 - if bitspp == 8: - data = data.reshape((h, w)) - data = data.astype(np.uint16) << 8 - elif bitspp in [10, 12]: - data = data.view(np.uint16) - data = data.reshape((h, w)) - data = data << (16 - bitspp) - else: - raise Exception('Bad bitspp:' + str(bitspp)) - - idx = bayer_pattern.find('R') - assert(idx != -1) - r0 = (idx % 2, idx // 2) - - idx = bayer_pattern.find('G') - assert(idx != -1) - g0 = (idx % 2, idx // 2) - - idx = bayer_pattern.find('G', idx + 1) - assert(idx != -1) - g1 = (idx % 2, idx // 2) - - idx = bayer_pattern.find('B') - assert(idx != -1) - b0 = (idx % 2, idx // 2) - - rgb = separate_components(data, r0, g0, g1, b0) - rgb = demosaic(rgb, r0, g0, g1, b0) - rgb = (rgb >> 8).astype(np.uint8) - - else: - rgb = None - - return rgb - - class QtRenderer: def __init__(self, state): self.state = state @@ -334,8 +144,7 @@ class MainWindow(QtWidgets.QWidget): qim = ImageQt(img).copy() pix = QtGui.QPixmap.fromImage(qim) else: - data = np.array(mfb.planes[0], dtype=np.uint8) - rgb = to_rgb(cfg.pixel_format, cfg.size, data) + rgb = camutils.mfb_to_rgb(mfb, cfg) if rgb is None: raise Exception('Format not supported: ' + cfg.pixel_format) diff --git a/src/py/libcamera/meson.build b/src/py/libcamera/meson.build index fbd33139..af8ba6a5 100644 --- a/src/py/libcamera/meson.build +++ b/src/py/libcamera/meson.build @@ -54,10 +54,16 @@ pycamera = shared_module('_libcamera', dependencies : pycamera_deps, cpp_args : pycamera_args) +# Generate symlinks so that we can use the module from the build dir + run_command('ln', '-fsT', '../../../../src/py/libcamera/__init__.py', meson.current_build_dir() / '__init__.py', check: true) +run_command('ln', '-fsT', '../../../../src/py/libcamera/utils', + meson.current_build_dir() / 'utils', + check: true) + install_data(['__init__.py'], install_dir : destdir) # \todo Generate stubs when building, and install them. diff --git a/src/py/libcamera/utils/__init__.py b/src/py/libcamera/utils/__init__.py new file mode 100644 index 00000000..5fa884ca --- /dev/null +++ b/src/py/libcamera/utils/__init__.py @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2022, Tomi Valkeinen + +from .conv import * diff --git a/src/py/cam/cam_qt.py b/src/py/libcamera/utils/conv.py similarity index 58% copy from src/py/cam/cam_qt.py copy to src/py/libcamera/utils/conv.py index 5753f0b2..71270671 100644 --- a/src/py/cam/cam_qt.py +++ b/src/py/libcamera/utils/conv.py @@ -3,20 +3,9 @@ # # Debayering code from PiCamera documentation -from io import BytesIO +from libcamera import MappedFrameBuffer, StreamConfiguration from numpy.lib.stride_tricks import as_strided -from PIL import Image -from PIL.ImageQt import ImageQt -from PyQt5 import QtCore, QtGui, QtWidgets import numpy as np -import sys - - -def rgb_to_pix(rgb): - img = Image.frombuffer('RGB', (rgb.shape[1], rgb.shape[0]), rgb) - qim = ImageQt(img).copy() - pix = QtGui.QPixmap.fromImage(qim) - return pix def separate_components(data, r0, g0, g1, b0): @@ -205,150 +194,7 @@ def to_rgb(fmt, size, data): return rgb -class QtRenderer: - def __init__(self, state): - self.state = state - - self.cm = state['cm'] - self.contexts = state['contexts'] - - def setup(self): - self.app = QtWidgets.QApplication([]) - - windows = [] - - for ctx in self.contexts: - camera = ctx['camera'] - - for stream in ctx['streams']: - fmt = stream.configuration.pixel_format - size = stream.configuration.size - - window = MainWindow(ctx, stream) - window.setAttribute(QtCore.Qt.WA_ShowWithoutActivating) - window.show() - windows.append(window) - - self.windows = windows - - def run(self): - camnotif = QtCore.QSocketNotifier(self.cm.efd, QtCore.QSocketNotifier.Read) - camnotif.activated.connect(lambda x: self.readcam()) - - keynotif = QtCore.QSocketNotifier(sys.stdin.fileno(), QtCore.QSocketNotifier.Read) - keynotif.activated.connect(lambda x: self.readkey()) - - print('Capturing...') - - self.app.exec() - - print('Exiting...') - - def readcam(self): - running = self.state['event_handler'](self.state) - - if not running: - self.app.quit() - - def readkey(self): - sys.stdin.readline() - self.app.quit() - - def request_handler(self, ctx, req): - buffers = req.buffers - - for stream, fb in buffers.items(): - wnd = next(wnd for wnd in self.windows if wnd.stream == stream) - - wnd.handle_request(stream, fb) - - self.state['request_prcessed'](ctx, req) - - def cleanup(self): - for w in self.windows: - w.close() - - -class MainWindow(QtWidgets.QWidget): - def __init__(self, ctx, stream): - super().__init__() - - self.ctx = ctx - self.stream = stream - - self.label = QtWidgets.QLabel() - - windowLayout = QtWidgets.QHBoxLayout() - self.setLayout(windowLayout) - - windowLayout.addWidget(self.label) - - controlsLayout = QtWidgets.QVBoxLayout() - windowLayout.addLayout(controlsLayout) - - windowLayout.addStretch() - - group = QtWidgets.QGroupBox('Info') - groupLayout = QtWidgets.QVBoxLayout() - group.setLayout(groupLayout) - controlsLayout.addWidget(group) - - lab = QtWidgets.QLabel(ctx['id']) - groupLayout.addWidget(lab) - - self.frameLabel = QtWidgets.QLabel() - groupLayout.addWidget(self.frameLabel) - - group = QtWidgets.QGroupBox('Properties') - groupLayout = QtWidgets.QVBoxLayout() - group.setLayout(groupLayout) - controlsLayout.addWidget(group) - - camera = ctx['camera'] - - for k, v in camera.properties.items(): - lab = QtWidgets.QLabel() - lab.setText(k + ' = ' + str(v)) - groupLayout.addWidget(lab) - - group = QtWidgets.QGroupBox('Controls') - groupLayout = QtWidgets.QVBoxLayout() - group.setLayout(groupLayout) - controlsLayout.addWidget(group) - - for k, (min, max, default) in camera.controls.items(): - lab = QtWidgets.QLabel() - lab.setText('{} = {}/{}/{}'.format(k, min, max, default)) - groupLayout.addWidget(lab) - - controlsLayout.addStretch() - - def buf_to_qpixmap(self, stream, fb): - with fb.mmap() as mfb: - cfg = stream.configuration - w, h = cfg.size - pitch = cfg.stride - - if cfg.pixel_format == 'MJPEG': - img = Image.open(BytesIO(mfb.planes[0])) - qim = ImageQt(img).copy() - pix = QtGui.QPixmap.fromImage(qim) - else: - data = np.array(mfb.planes[0], dtype=np.uint8) - rgb = to_rgb(cfg.pixel_format, cfg.size, data) - - if rgb is None: - raise Exception('Format not supported: ' + cfg.pixel_format) - - pix = rgb_to_pix(rgb) - - return pix - - def handle_request(self, stream, fb): - ctx = self.ctx - - pix = self.buf_to_qpixmap(stream, fb) - self.label.setPixmap(pix) - - self.frameLabel.setText('Queued: {}\nDone: {}\nFps: {:.2f}' - .format(ctx['reqs-queued'], ctx['reqs-completed'], ctx['fps'])) +def mfb_to_rgb(mfb:MappedFrameBuffer, cfg:StreamConfiguration): + data = np.array(mfb.planes[0], dtype=np.uint8) + rgb = to_rgb(cfg.pixel_format, cfg.size, data) + return rgb From patchwork Mon May 16 14:10:17 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 15915 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 54B38C326C for ; Mon, 16 May 2022 14:11:01 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 02A0C65678; Mon, 16 May 2022 16:11:00 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1652710261; bh=IP2QL/5PkYu8iWZ2/e8dNVwMu0kVrrqLMzzix+9M7Vk=; 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=JsRrYQR85pWh+muBYEVB84l5fuJylSDYa12Pk9kGdROCGchyJjY6k6r9Y6hmNAzVI m7HXkdcqAsqAZsb2dv/eprCeRdsW5n4lbOti4Y/ZIUrILbSA9hBfSTEWEuGzKdb10Q Ueugaoivr9eSsT8o2jC8t5ilqk1qy9SXzbnyRsXMpUWXajF8ye4YmcpCfrJBqe6Kyp SBSuSMy+SSsgGx1qamlUGbZ3F/bMIfhuJ2sxbVKPfOfQz+pi0JPpFeXXfBp1Wox2gp +VvoZ8/k9rBqfy72reIcqlvSTDSJaUgh/fgewPgSoMLEgj/bW6RwxwXwPw/zNrfo4D nOnLq1JSzqoYg== 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 7DD8E65667 for ; Mon, 16 May 2022 16:10:52 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="BzoYZ+k1"; dkim-atps=neutral Received: from deskari.lan (91-156-85-209.elisa-laajakaista.fi [91.156.85.209]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id EC6D659D; Mon, 16 May 2022 16:10:51 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1652710252; bh=IP2QL/5PkYu8iWZ2/e8dNVwMu0kVrrqLMzzix+9M7Vk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=BzoYZ+k1jHQFC6jrlye3iaDj3t/zanK2ns8Svwjewm+UcgKMFTgNRC/1J1B1bdH8K R6PK9cXdfvVJtGeW4xvnJmeWr/qS+iSRFePhH9VfiJLG65P4+3lsJQfaFTnjojq3WJ 8i0tmW6lbxhfqBdhnSLHl5Enr2mj7Ge50M35aIbA= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Mon, 16 May 2022 17:10:17 +0300 Message-Id: <20220516141022.96327-10-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> References: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 09/14] py: conv.py: minor cleanups 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: Tomi Valkeinen via libcamera-devel From: Tomi Valkeinen Reply-To: Tomi Valkeinen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Combine separate_components() with demosaic() and clean up the comments. Signed-off-by: Tomi Valkeinen --- src/py/libcamera/utils/conv.py | 54 ++++------------------------------ 1 file changed, 6 insertions(+), 48 deletions(-) diff --git a/src/py/libcamera/utils/conv.py b/src/py/libcamera/utils/conv.py index 71270671..2e483003 100644 --- a/src/py/libcamera/utils/conv.py +++ b/src/py/libcamera/utils/conv.py @@ -8,19 +8,8 @@ from numpy.lib.stride_tricks import as_strided import numpy as np -def separate_components(data, r0, g0, g1, b0): - # Now to split the data up into its red, green, and blue components. The - # Bayer pattern of the OV5647 sensor is BGGR. In other words the first - # row contains alternating green/blue elements, the second row contains - # alternating red/green elements, and so on as illustrated below: - # - # GBGBGBGBGBGBGB - # RGRGRGRGRGRGRG - # GBGBGBGBGBGBGB - # RGRGRGRGRGRGRG - # - # Please note that if you use vflip or hflip to change the orientation - # of the capture, you must flip the Bayer pattern accordingly +def demosaic(data, r0, g0, g1, b0): + # Separate the components from the Bayer data to RGB planes rgb = np.zeros(data.shape + (3,), dtype=data.dtype) rgb[r0[1]::2, r0[0]::2, 0] = data[r0[1]::2, r0[0]::2] # Red @@ -28,17 +17,9 @@ def separate_components(data, r0, g0, g1, b0): rgb[g1[1]::2, g1[0]::2, 1] = data[g1[1]::2, g1[0]::2] # Green rgb[b0[1]::2, b0[0]::2, 2] = data[b0[1]::2, b0[0]::2] # Blue - return rgb - - -def demosaic(rgb, r0, g0, g1, b0): - # At this point we now have the raw Bayer data with the correct values - # and colors but the data still requires de-mosaicing and - # post-processing. If you wish to do this yourself, end the script here! - # # Below we present a fairly naive de-mosaic method that simply # calculates the weighted average of a pixel based on the pixels - # surrounding it. The weighting is provided b0[1] a b0[1]te representation of + # surrounding it. The weighting is provided by a byte representation of # the Bayer filter which we construct first: bayer = np.zeros(rgb.shape, dtype=np.uint8) @@ -58,29 +39,6 @@ def demosaic(rgb, r0, g0, g1, b0): borders = (window[0] - 1, window[1] - 1) border = (borders[0] // 2, borders[1] // 2) - # rgb_pad = np.zeros(( - # rgb.shape[0] + borders[0], - # rgb.shape[1] + borders[1], - # rgb.shape[2]), dtype=rgb.dtype) - # rgb_pad[ - # border[0]:rgb_pad.shape[0] - border[0], - # border[1]:rgb_pad.shape[1] - border[1], - # :] = rgb - # rgb = rgb_pad - # - # bayer_pad = np.zeros(( - # bayer.shape[0] + borders[0], - # bayer.shape[1] + borders[1], - # bayer.shape[2]), dtype=bayer.dtype) - # bayer_pad[ - # border[0]:bayer_pad.shape[0] - border[0], - # border[1]:bayer_pad.shape[1] - border[1], - # :] = bayer - # bayer = bayer_pad - - # In numpy >=1.7.0 just use np.pad (version in Raspbian is 1.6.2 at the - # time of writing...) - # rgb = np.pad(rgb, [ (border[0], border[0]), (border[1], border[1]), @@ -157,7 +115,7 @@ def to_rgb(fmt, size, data): bayer_pattern = fmt[1:5] bitspp = int(fmt[5:]) - # TODO: shifting leaves the lowest bits 0 + # \todo shifting leaves the lowest bits 0 if bitspp == 8: data = data.reshape((h, w)) data = data.astype(np.uint16) << 8 @@ -184,8 +142,7 @@ def to_rgb(fmt, size, data): assert(idx != -1) b0 = (idx % 2, idx // 2) - rgb = separate_components(data, r0, g0, g1, b0) - rgb = demosaic(rgb, r0, g0, g1, b0) + rgb = demosaic(data, r0, g0, g1, b0) rgb = (rgb >> 8).astype(np.uint8) else: @@ -194,6 +151,7 @@ def to_rgb(fmt, size, data): return rgb +# A naive format conversion to 24-bit RGB def mfb_to_rgb(mfb:MappedFrameBuffer, cfg:StreamConfiguration): data = np.array(mfb.planes[0], dtype=np.uint8) rgb = to_rgb(cfg.pixel_format, cfg.size, data) From patchwork Mon May 16 14:10:18 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 15916 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 2EB6FC326D for ; Mon, 16 May 2022 14:11:02 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D17676567A; Mon, 16 May 2022 16:11:01 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1652710261; bh=H4frClzkoxxtEje2/WXL/DB0rR1BtPuKAfqzehMsIzM=; 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=m5C0vuHdprWmZjrAufnQZzfFRu48Glw9HUOoSp3p3Wxmvgf4wgp+b6hGdmaKI7r3f iCeFlQrCFfgTsvSHvfnqdI4fEAefjlElyPYnzTj+Zrp4TkSJDs2yjub/pXdQGfuNCQ rhC6E6OzzG3gAzWv/CMlfOIOOTf43Wq0+RqrcdRwFzyvSbaQXycei/Aet8k1fx5+pD 3FDZSTZRR5nIBAXQIT5cEbw9+k5bVRwu13n8QM9EaWelzZ0gGbsmUV4w4tbRQSfIuE Vw0t0CjVaHjkUUyZNnTSXZi7avuLFz53DCY/4GqT/VkFjjefg6UBPYRlHY6DDKNa6Y PBHB1WD3Han2A== 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 119DC65668 for ; Mon, 16 May 2022 16:10:53 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="gnxD55Zt"; dkim-atps=neutral Received: from deskari.lan (91-156-85-209.elisa-laajakaista.fi [91.156.85.209]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 741EF484; Mon, 16 May 2022 16:10:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1652710252; bh=H4frClzkoxxtEje2/WXL/DB0rR1BtPuKAfqzehMsIzM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=gnxD55ZtJRkrk0Yb1z+C4FdNsk8BE12aWadVr7TcqoZujdx3EDxppwAASUGjGreoQ TiEUzDVLCLe2SM5A1xKzgUn9U9nHwQjiNcNg+XZtONzdtqNPEkq7XjjQRiswg20Xfh nfCjMVZZ1bs2fR1BHzvYJVkgDhS81ISLmrA1IKek= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Mon, 16 May 2022 17:10:18 +0300 Message-Id: <20220516141022.96327-11-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> References: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 10/14] py: implement PixelFormat class 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: Tomi Valkeinen via libcamera-devel From: Tomi Valkeinen Reply-To: Tomi Valkeinen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Implement PixelFormat bindings properly with a PixelFormat class. Change the bindings to use the new class instead of a string. Signed-off-by: Tomi Valkeinen --- src/py/cam/cam.py | 4 +-- src/py/cam/cam_kms.py | 9 +----- src/py/cam/cam_qt.py | 2 +- src/py/cam/cam_qtgl.py | 17 +----------- src/py/cam/gl_helpers.py | 8 ------ src/py/libcamera/pymain.cpp | 51 ++++++++++++++++++++-------------- src/py/libcamera/utils/conv.py | 2 ++ 7 files changed, 37 insertions(+), 56 deletions(-) diff --git a/src/py/cam/cam.py b/src/py/cam/cam.py index c7da97d7..63c67126 100755 --- a/src/py/cam/cam.py +++ b/src/py/cam/cam.py @@ -80,7 +80,7 @@ def do_cmd_info(ctx): formats = stream_config.formats for fmt in formats.pixel_formats: - print('\t * Pixelformat:', fmt, formats.range(fmt)) + print('\t * Pixelformat:', fmt.name, formats.range(fmt)) for size in formats.sizes(fmt): print('\t -', size) @@ -164,7 +164,7 @@ def configure(ctx): stream_config.size = (stream_opts['width'], stream_opts['height']) if 'pixelformat' in stream_opts: - stream_config.pixel_format = stream_opts['pixelformat'] + stream_config.pixel_format = libcam.PixelFormat.from_name(stream_opts['pixelformat']) stat = camconfig.validate() diff --git a/src/py/cam/cam_kms.py b/src/py/cam/cam_kms.py index ae6be277..7d11564b 100644 --- a/src/py/cam/cam_kms.py +++ b/src/py/cam/cam_kms.py @@ -5,13 +5,6 @@ import pykms import selectors import sys -FMT_MAP = { - 'RGB888': pykms.PixelFormat.RGB888, - 'YUYV': pykms.PixelFormat.YUYV, - 'ARGB8888': pykms.PixelFormat.ARGB8888, - 'XRGB8888': pykms.PixelFormat.XRGB8888, -} - class KMSRenderer: def __init__(self, state): @@ -118,7 +111,7 @@ class KMSRenderer: cfg = stream.configuration fmt = cfg.pixel_format - fmt = FMT_MAP[fmt] + fmt = pykms.PixelFormat(fmt.fourcc) plane = self.resman.reserve_generic_plane(self.crtc, fmt) assert(plane is not None) diff --git a/src/py/cam/cam_qt.py b/src/py/cam/cam_qt.py index dc5219eb..64f49f33 100644 --- a/src/py/cam/cam_qt.py +++ b/src/py/cam/cam_qt.py @@ -139,7 +139,7 @@ class MainWindow(QtWidgets.QWidget): w, h = cfg.size pitch = cfg.stride - if cfg.pixel_format == 'MJPEG': + if cfg.pixel_format.name == 'MJPEG': img = Image.open(BytesIO(mfb.planes[0])) qim = ImageQt(img).copy() pix = QtGui.QPixmap.fromImage(qim) diff --git a/src/py/cam/cam_qtgl.py b/src/py/cam/cam_qtgl.py index 8a95994e..261accb8 100644 --- a/src/py/cam/cam_qtgl.py +++ b/src/py/cam/cam_qtgl.py @@ -30,14 +30,6 @@ from OpenGL.GL import shaders from gl_helpers import * -# libcamera format string -> DRM fourcc -FMT_MAP = { - 'RGB888': 'RG24', - 'XRGB8888': 'XR24', - 'ARGB8888': 'AR24', - 'YUYV': 'YUYV', -} - class EglState: def __init__(self): @@ -204,12 +196,6 @@ class MainWindow(QtWidgets.QWidget): self.current[ctx['idx']] = [] for stream in ctx['streams']: - fmt = stream.configuration.pixel_format - size = stream.configuration.size - - if fmt not in FMT_MAP: - raise Exception('Unsupported pixel format: ' + str(fmt)) - self.textures[stream] = None num_tiles = len(self.textures) @@ -281,8 +267,7 @@ class MainWindow(QtWidgets.QWidget): def create_texture(self, stream, fb): cfg = stream.configuration - fmt = cfg.pixel_format - fmt = str_to_fourcc(FMT_MAP[fmt]) + fmt = cfg.pixel_format.fourcc w, h = cfg.size attribs = [ diff --git a/src/py/cam/gl_helpers.py b/src/py/cam/gl_helpers.py index ac5e6889..53b3e9df 100644 --- a/src/py/cam/gl_helpers.py +++ b/src/py/cam/gl_helpers.py @@ -30,14 +30,6 @@ def getglEGLImageTargetTexture2DOES(): glEGLImageTargetTexture2DOES = getglEGLImageTargetTexture2DOES() -# \todo This can be dropped when we have proper PixelFormat bindings -def str_to_fourcc(str): - assert(len(str) == 4) - fourcc = 0 - for i, v in enumerate([ord(c) for c in str]): - fourcc |= v << (i * 8) - return fourcc - def get_gl_extensions(): n = GLint() diff --git a/src/py/libcamera/pymain.cpp b/src/py/libcamera/pymain.cpp index af22205e..cc2ddee5 100644 --- a/src/py/libcamera/pymain.cpp +++ b/src/py/libcamera/pymain.cpp @@ -8,7 +8,6 @@ /* * \todo Add geometry classes (Point, Rectangle...) * \todo Add bindings for the ControlInfo class - * \todo Add bindings for the PixelFormat class */ #include @@ -173,6 +172,7 @@ PYBIND11_MODULE(_libcamera, m) auto pyColorSpaceTransferFunction = py::enum_(pyColorSpace, "TransferFunction"); auto pyColorSpaceYcbcrEncoding = py::enum_(pyColorSpace, "YcbcrEncoding"); auto pyColorSpaceRange = py::enum_(pyColorSpace, "Range"); + auto pyPixelFormat = py::class_(m, "PixelFormat"); /* Global functions */ m.def("log_set_level", &logSetLevel); @@ -404,14 +404,7 @@ PYBIND11_MODULE(_libcamera, m) self.size.width = std::get<0>(size); self.size.height = std::get<1>(size); }) - .def_property( - "pixel_format", - [](StreamConfiguration &self) { - return self.pixelFormat.toString(); - }, - [](StreamConfiguration &self, std::string fmt) { - self.pixelFormat = PixelFormat::fromString(fmt); - }) + .def_readwrite("pixel_format", &StreamConfiguration::pixelFormat) .def_readwrite("stride", &StreamConfiguration::stride) .def_readwrite("frame_size", &StreamConfiguration::frameSize) .def_readwrite("buffer_count", &StreamConfiguration::bufferCount) @@ -420,22 +413,15 @@ PYBIND11_MODULE(_libcamera, m) .def_readwrite("color_space", &StreamConfiguration::colorSpace); pyStreamFormats - .def_property_readonly("pixel_formats", [](StreamFormats &self) { - std::vector fmts; - for (auto &fmt : self.pixelformats()) - fmts.push_back(fmt.toString()); - return fmts; - }) - .def("sizes", [](StreamFormats &self, const std::string &pixelFormat) { - auto fmt = PixelFormat::fromString(pixelFormat); + .def_property_readonly("pixel_formats", &StreamFormats::pixelformats) + .def("sizes", [](StreamFormats &self, const PixelFormat &pixelFormat) { std::vector> fmts; - for (const auto &s : self.sizes(fmt)) + for (const auto &s : self.sizes(pixelFormat)) fmts.push_back(std::make_tuple(s.width, s.height)); return fmts; }) - .def("range", [](StreamFormats &self, const std::string &pixelFormat) { - auto fmt = PixelFormat::fromString(pixelFormat); - const auto &range = self.range(fmt); + .def("range", [](StreamFormats &self, const PixelFormat &pixelFormat) { + const auto &range = self.range(pixelFormat); return make_tuple(std::make_tuple(range.hStep, range.vStep), std::make_tuple(range.min.width, range.min.height), std::make_tuple(range.max.width, range.max.height)); @@ -648,4 +634,27 @@ PYBIND11_MODULE(_libcamera, m) pyColorSpaceRange .value("Full", ColorSpace::Range::Full) .value("Limited", ColorSpace::Range::Limited); + + pyPixelFormat + .def(py::init<>()) + .def(py::init()) + .def_property_readonly("fourcc", &PixelFormat::fourcc) + .def_property_readonly("modifier", &PixelFormat::modifier) + .def_property_readonly("name", &PixelFormat::toString) + .def(py::self == py::self) + .def("__str__", [](const PixelFormat &self) { + return ""; + }) + .def_static("from_name", [](const std::string &name) { + return PixelFormat::fromString(name); + }) + .def_static("from_fourcc", [](const std::string &fourcc) { + if (fourcc.size() != 4) + throw std::invalid_argument("Invalid fourcc length"); + + uint32_t v = fourcc[0] | (fourcc[1] << 8) | + (fourcc[2] << 16) | (fourcc[3] << 24); + + return PixelFormat(v); + }); } diff --git a/src/py/libcamera/utils/conv.py b/src/py/libcamera/utils/conv.py index 2e483003..30f6733e 100644 --- a/src/py/libcamera/utils/conv.py +++ b/src/py/libcamera/utils/conv.py @@ -76,6 +76,8 @@ def to_rgb(fmt, size, data): w = size[0] h = size[1] + fmt = fmt.name + if fmt == 'YUYV': # YUV422 yuyv = data.reshape((h, w // 2 * 4)) From patchwork Mon May 16 14:10:19 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 15917 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 EB632C326F for ; Mon, 16 May 2022 14:11:02 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 9E40F65679; Mon, 16 May 2022 16:11:02 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1652710262; bh=h3HTxTU84cyLpKuYECAq/ub53xCYyQhLdSJVIez0dRk=; 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=u/ZLjW83PCp30ZfNah6gMQheEt+OOJJWSLc0cZTQe8Mg8XDfrjfPOc5o66vkJhMuw uU7weD+bTNyu9pIcxvMmEoc5/w1i2jhftvQqy+qnH+9uyRj8O1AAfgO2g9HBa27PX7 Jm82i8t7jzXn4rA0CJ/cU60TBg8NpUAbFJt+JZfGGPtYMh8FZx7YtSqOPkik1bioMu DKNeve8A8gcZswF7k6OqnrdV8yxnaxHhqeR5Z2qHf1yCjUY6+Pwpqpbk6BifkKQvw9 tJ8HN/vxV5e6oQSfh7ASD7rKGXIds8Y35X6y/iUe2hwZEaJeosAKn6Ncw1kp+G20ln 8cgcDfjf+lmlA== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 853B16565D for ; Mon, 16 May 2022 16:10:53 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="MwZg0L26"; dkim-atps=neutral Received: from deskari.lan (91-156-85-209.elisa-laajakaista.fi [91.156.85.209]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 01EF0898; Mon, 16 May 2022 16:10:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1652710253; bh=h3HTxTU84cyLpKuYECAq/ub53xCYyQhLdSJVIez0dRk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MwZg0L26VHM0fCydYo51bPvb0JsNNZ4ST8Fc/vV4sGfg8wcf8oipzdpy91FA4qIft UUKdP9f579YKfH5UjPFvqt8HovIjYIty3r1NNzQYY4tR7jLTtyHvR7sOIJPMPkBBzx dwz8ESMK3THWjpwrFlGGqBce+iCIx+pjk0Qvl7jI= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Mon, 16 May 2022 17:10:19 +0300 Message-Id: <20220516141022.96327-12-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> References: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 11/14] py: add geometry classes 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: Tomi Valkeinen via libcamera-devel From: Tomi Valkeinen Reply-To: Tomi Valkeinen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add libcamera's geometry classes to the Python bindings. Note that this commit only adds the classes, but they are not used anywhere yet. Signed-off-by: Tomi Valkeinen --- src/py/libcamera/meson.build | 1 + src/py/libcamera/pygeometry.cpp | 104 ++++++++++++++++++++++++++++++++ src/py/libcamera/pymain.cpp | 2 + 3 files changed, 107 insertions(+) create mode 100644 src/py/libcamera/pygeometry.cpp diff --git a/src/py/libcamera/meson.build b/src/py/libcamera/meson.build index af8ba6a5..12e006e7 100644 --- a/src/py/libcamera/meson.build +++ b/src/py/libcamera/meson.build @@ -14,6 +14,7 @@ pybind11_dep = pybind11_proj.get_variable('pybind11_dep') pycamera_sources = files([ 'pyenums.cpp', + 'pygeometry.cpp', 'pymain.cpp', ]) diff --git a/src/py/libcamera/pygeometry.cpp b/src/py/libcamera/pygeometry.cpp new file mode 100644 index 00000000..2cd1432e --- /dev/null +++ b/src/py/libcamera/pygeometry.cpp @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022, Tomi Valkeinen + * + * Python bindings - Geometry classes + */ + +#include + +#include +#include + +#include +#include +#include + +namespace py = pybind11; + +using namespace libcamera; + +void init_py_geometry(py::module &m) +{ + py::class_(m, "Point") + .def(py::init<>()) + .def(py::init()) + .def_readwrite("x", &Point::x) + .def_readwrite("y", &Point::y) + .def(py::self == py::self) + .def(-py::self) + .def("__str__", &Point::toString) + .def("__repr__", [](const Point &self) { + return "libcamera.Point(" + std::to_string(self.x) + ", " + std::to_string(self.y) + ")"; + }); + + py::class_(m, "Size") + .def(py::init<>()) + .def(py::init()) + .def_readwrite("width", &Size::width) + .def_readwrite("height", &Size::height) + .def_property_readonly("is_null", &Size::isNull) + .def(py::self == py::self) + .def(py::self * float()) + .def(py::self / float()) + .def(py::self *= float()) + .def(py::self /= float()) + .def("__str__", &Size::toString) + .def("__repr__", [](const Size &self) { + return "libcamera.Size(" + std::to_string(self.width) + ", " + std::to_string(self.height) + ")"; + }); + + py::class_(m, "SizeRange") + .def(py::init<>()) + .def(py::init()) + .def(py::init()) + .def(py::init()) + .def(py::init<>([](const std::array &s) { + return SizeRange(Size(std::get<0>(s), std::get<1>(s))); + })) + .def(py::init<>([](const std::array &min, const std::array &max) { + return SizeRange(Size(std::get<0>(min), std::get<1>(min)), + Size(std::get<0>(max), std::get<1>(max))); + })) + .def(py::init<>([](const std::array &min, const std::array &max, + unsigned int hStep, unsigned int vStep) { + return SizeRange(Size(std::get<0>(min), std::get<1>(min)), + Size(std::get<0>(max), std::get<1>(max)), + hStep, vStep); + })) + .def_readwrite("min", &SizeRange::min) + .def_readwrite("max", &SizeRange::max) + .def_readwrite("hStep", &SizeRange::hStep) + .def_readwrite("vStep", &SizeRange::vStep) + .def(py::self == py::self) + .def("__str__", &SizeRange::toString) + .def("__repr__", [](const SizeRange &self) { + return py::str("libcamera.SizeRange(({}, {}), ({}, {}), {}, {})") + .format(self.min.width, self.min.height, + self.max.width, self.max.height, + self.hStep, self.vStep); + }); + + py::class_(m, "Rectangle") + .def(py::init<>()) + .def(py::init()) + .def(py::init<>([](int x, int y, const std::array &s) { + return Rectangle(x, y, std::get<0>(s), std::get<1>(s)); + })) + .def(py::init()) + .def(py::init()) + .def_readwrite("x", &Rectangle::x) + .def_readwrite("y", &Rectangle::y) + .def_readwrite("width", &Rectangle::width) + .def_readwrite("height", &Rectangle::height) + .def_property_readonly("is_null", &Rectangle::isNull) + .def_property_readonly("center", &Rectangle::center) + .def_property_readonly("size", &Rectangle::size) + .def_property_readonly("topLeft", &Rectangle::topLeft) + .def(py::self == py::self) + .def("__str__", &Rectangle::toString) + .def("__repr__", [](const Rectangle &self) { + return py::str("libcamera.Rectangle({}, {}, {}, {})") + .format(self.x, self.y, self.width, self.height); + }); +} diff --git a/src/py/libcamera/pymain.cpp b/src/py/libcamera/pymain.cpp index cc2ddee5..1dd70d9c 100644 --- a/src/py/libcamera/pymain.cpp +++ b/src/py/libcamera/pymain.cpp @@ -137,11 +137,13 @@ static void handleRequestCompleted(Request *req) void init_pyenums(py::module &m); void init_pyenums_generated(py::module &m); +void init_py_geometry(py::module &m); PYBIND11_MODULE(_libcamera, m) { init_pyenums(m); init_pyenums_generated(m); + init_py_geometry(m); /* Forward declarations */ From patchwork Mon May 16 14:10:20 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 15918 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 D0D20C326E for ; Mon, 16 May 2022 14:11:03 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 604E86567C; Mon, 16 May 2022 16:11:03 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1652710263; bh=qO9eZeY+UmGt+WPdTtX/QwrNzHBKP0FK3kHiLR9Xleo=; 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=l9BhMmOlCwLXotjb83LG04xPpewa082aY9bXdhqRAyv+d4sApqthr+9Up4uYxA8MS mZlDutP3RKNg2HwTXW8D4rAyzgiKASSLngATdN/H4YJQemjp6nm5LmBv1m/4IwldJ7 CEfeBioxXQh4MHPKIa6d++RIRQYUPy3AURt9rxJRKD2ZqIS40UIoQ3izwDKJWBG7I6 u+A7813TXTrKD5maHsvWuQCzcUTstgBKs+s4+Vx7KSAya3/R1UHIxQQXH4q6fi+zaI B8Cqo/FAD8/SaeYJvS/xLbF8j/yrGw2jVw3flzb5egsjd70zoU+o0g24j6CrtvVpHu YRKthF6Z2ApSA== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1BBB561FB8 for ; Mon, 16 May 2022 16:10:54 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="DxZslWE/"; dkim-atps=neutral Received: from deskari.lan (91-156-85-209.elisa-laajakaista.fi [91.156.85.209]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 80E8F48F; Mon, 16 May 2022 16:10:53 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1652710253; bh=qO9eZeY+UmGt+WPdTtX/QwrNzHBKP0FK3kHiLR9Xleo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=DxZslWE/SwRBloosc1sELMO5ZDKyLl/RDXuwkkQoW0s76GDgsbc3cDIdJTWcm2xmC 9vZDoVBXRNphBuU8yrYjHGrXW1keT50ik++nacwIHuyfYfuKSIPTf7EMbunCEeVvyJ CztHX9hsuCfPYgl5qkirvkNYGnJuA7pcPPOzHLhA= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Mon, 16 May 2022 17:10:20 +0300 Message-Id: <20220516141022.96327-13-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> References: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 12/14] py: use geometry classes 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: Tomi Valkeinen via libcamera-devel From: Tomi Valkeinen Reply-To: Tomi Valkeinen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Now that we have proper geometry classes in the Python bindings, change the existing bindings and the .py files accordingly. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- src/py/cam/cam.py | 7 ++++-- src/py/cam/cam_kms.py | 3 ++- src/py/cam/cam_qt.py | 3 ++- src/py/cam/cam_qtgl.py | 3 ++- src/py/libcamera/pymain.cpp | 41 ++++++++-------------------------- src/py/libcamera/utils/conv.py | 4 ++-- 6 files changed, 22 insertions(+), 39 deletions(-) diff --git a/src/py/cam/cam.py b/src/py/cam/cam.py index 63c67126..347175b7 100755 --- a/src/py/cam/cam.py +++ b/src/py/cam/cam.py @@ -160,8 +160,11 @@ def configure(ctx): for idx, stream_opts in enumerate(streams): stream_config = camconfig.at(idx) - if 'width' in stream_opts and 'height' in stream_opts: - stream_config.size = (stream_opts['width'], stream_opts['height']) + if 'width' in stream_opts: + stream_config.size.width = stream_opts['width'] + + if 'height' in stream_opts: + stream_config.size.height = stream_opts['height'] if 'pixelformat' in stream_opts: stream_config.pixel_format = libcam.PixelFormat.from_name(stream_opts['pixelformat']) diff --git a/src/py/cam/cam_kms.py b/src/py/cam/cam_kms.py index 7d11564b..da3dd4e0 100644 --- a/src/py/cam/cam_kms.py +++ b/src/py/cam/cam_kms.py @@ -125,7 +125,8 @@ class KMSRenderer: }) for fb in ctx['allocator'].buffers(stream): - w, h = cfg.size + w = cfg.size.width + h = cfg.size.height stride = cfg.stride fd = fb.fd(0) drmfb = pykms.DmabufFramebuffer(self.card, w, h, fmt, diff --git a/src/py/cam/cam_qt.py b/src/py/cam/cam_qt.py index 64f49f33..8bef9b57 100644 --- a/src/py/cam/cam_qt.py +++ b/src/py/cam/cam_qt.py @@ -136,7 +136,8 @@ class MainWindow(QtWidgets.QWidget): def buf_to_qpixmap(self, stream, fb): with fb.mmap() as mfb: cfg = stream.configuration - w, h = cfg.size + w = cfg.size.width + h = cfg.size.height pitch = cfg.stride if cfg.pixel_format.name == 'MJPEG': diff --git a/src/py/cam/cam_qtgl.py b/src/py/cam/cam_qtgl.py index 261accb8..4bbcda6c 100644 --- a/src/py/cam/cam_qtgl.py +++ b/src/py/cam/cam_qtgl.py @@ -268,7 +268,8 @@ class MainWindow(QtWidgets.QWidget): def create_texture(self, stream, fb): cfg = stream.configuration fmt = cfg.pixel_format.fourcc - w, h = cfg.size + w = cfg.size.width + h = cfg.size.height attribs = [ EGL_WIDTH, w, diff --git a/src/py/libcamera/pymain.cpp b/src/py/libcamera/pymain.cpp index 1dd70d9c..d7bd71ef 100644 --- a/src/py/libcamera/pymain.cpp +++ b/src/py/libcamera/pymain.cpp @@ -6,7 +6,6 @@ */ /* - * \todo Add geometry classes (Point, Rectangle...) * \todo Add bindings for the ControlInfo class */ @@ -61,11 +60,11 @@ static py::object controlValueToPy(const ControlValue &cv) return py::cast(cv.get()); case ControlTypeRectangle: { const Rectangle *v = reinterpret_cast(cv.data().data()); - return py::make_tuple(v->x, v->y, v->width, v->height); + return py::cast(v); } case ControlTypeSize: { const Size *v = reinterpret_cast(cv.data().data()); - return py::make_tuple(v->width, v->height); + return py::cast(v); } case ControlTypeNone: default: @@ -99,14 +98,10 @@ static ControlValue pyToControlValue(const py::object &ob, ControlType type) return controlValueMaybeArray(ob); case ControlTypeString: return ControlValue(ob.cast()); - case ControlTypeRectangle: { - auto array = ob.cast>(); - return ControlValue(Rectangle(array[0], array[1], array[2], array[3])); - } - case ControlTypeSize: { - auto array = ob.cast>(); - return ControlValue(Size(array[0], array[1])); - } + case ControlTypeRectangle: + return ControlValue(ob.cast()); + case ControlTypeSize: + return ControlValue(ob.cast()); case ControlTypeNone: default: throw std::runtime_error("Control type not implemented"); @@ -397,15 +392,7 @@ PYBIND11_MODULE(_libcamera, m) .def("__str__", &StreamConfiguration::toString) .def_property_readonly("stream", &StreamConfiguration::stream, py::return_value_policy::reference_internal) - .def_property( - "size", - [](StreamConfiguration &self) { - return std::make_tuple(self.size.width, self.size.height); - }, - [](StreamConfiguration &self, std::tuple size) { - self.size.width = std::get<0>(size); - self.size.height = std::get<1>(size); - }) + .def_readwrite("size", &StreamConfiguration::size) .def_readwrite("pixel_format", &StreamConfiguration::pixelFormat) .def_readwrite("stride", &StreamConfiguration::stride) .def_readwrite("frame_size", &StreamConfiguration::frameSize) @@ -416,18 +403,8 @@ PYBIND11_MODULE(_libcamera, m) pyStreamFormats .def_property_readonly("pixel_formats", &StreamFormats::pixelformats) - .def("sizes", [](StreamFormats &self, const PixelFormat &pixelFormat) { - std::vector> fmts; - for (const auto &s : self.sizes(pixelFormat)) - fmts.push_back(std::make_tuple(s.width, s.height)); - return fmts; - }) - .def("range", [](StreamFormats &self, const PixelFormat &pixelFormat) { - const auto &range = self.range(pixelFormat); - return make_tuple(std::make_tuple(range.hStep, range.vStep), - std::make_tuple(range.min.width, range.min.height), - std::make_tuple(range.max.width, range.max.height)); - }); + .def("sizes", &StreamFormats::sizes) + .def("range", &StreamFormats::range); pyFrameBufferAllocator .def(py::init>(), py::keep_alive<1, 2>()) diff --git a/src/py/libcamera/utils/conv.py b/src/py/libcamera/utils/conv.py index 30f6733e..5a4bc282 100644 --- a/src/py/libcamera/utils/conv.py +++ b/src/py/libcamera/utils/conv.py @@ -73,8 +73,8 @@ def demosaic(data, r0, g0, g1, b0): def to_rgb(fmt, size, data): - w = size[0] - h = size[1] + w = size.width + h = size.height fmt = fmt.name From patchwork Mon May 16 14:10:21 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 15919 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 A1568C3270 for ; Mon, 16 May 2022 14:11:04 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4B3C96567F; Mon, 16 May 2022 16:11:04 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1652710264; bh=8Xe5samNh0wR/IKpHFo8took51Ue1xe1NTyR2vXitCA=; 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=zzlcmBCIbMTht+bCgFvF5rGp266/yGNjdegmISplyc2/q/IsokZHJVxjAkdNdpIVV 0XeH5GaU83/zc+GDOg38L4CoR5qdmSgpAl1f3YcvnHTHK8Or4A1XIkttp0AioDiVvW HB+P4OF7UM0RYpA8e/akOEoCHwlHP7qW1GNPKZVAhsUngWEqrg52yFGj41UyHfCXXb YUE/DtgHRZuaOkAIF+w7MpGeofQlnoeuKxXsuVr69tYTm4JxfuRDcPc2GFjJvEfoi4 rVrLXdDMg5S5iCy+j7rYdd/pPNo0HfP3KKTdlEz78ojCd/bAVT1FwhK0P/RVGsM2GZ g0Qaif19wLp5w== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id A3EC26566E for ; Mon, 16 May 2022 16:10:54 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="n0DFthjM"; dkim-atps=neutral Received: from deskari.lan (91-156-85-209.elisa-laajakaista.fi [91.156.85.209]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 0D50A563; Mon, 16 May 2022 16:10:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1652710254; bh=8Xe5samNh0wR/IKpHFo8took51Ue1xe1NTyR2vXitCA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=n0DFthjMiKztvHaRzWH2ZrIpfrxROAd61AJbmd6vLusdVSgEN+cUK95ggInYpKdUq a66Zft7fQC8jX8A1Q+jvH8bC3donNwBjCpG6tHo5NvahkTjvk0a//4M81/8y8h9wzs 7XFBY5bAiLcCgyrJNFm1pHREZm6Y3itHBgvjKqkI= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Mon, 16 May 2022 17:10:21 +0300 Message-Id: <20220516141022.96327-14-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> References: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 13/14] py: cam_kms: support multiplanar formats 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: Tomi Valkeinen via libcamera-devel From: Tomi Valkeinen Reply-To: Tomi Valkeinen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Support multiplanar formats in the kms renderer. Tested with RPi and NV12. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- src/py/cam/cam_kms.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/py/cam/cam_kms.py b/src/py/cam/cam_kms.py index da3dd4e0..90aac5f6 100644 --- a/src/py/cam/cam_kms.py +++ b/src/py/cam/cam_kms.py @@ -127,10 +127,16 @@ class KMSRenderer: for fb in ctx['allocator'].buffers(stream): w = cfg.size.width h = cfg.size.height - stride = cfg.stride - fd = fb.fd(0) + fds = [] + strides = [] + offsets = [] + for i in range(fb.num_planes): + fds.append(fb.fd(i)) + strides.append(cfg.stride) + offsets.append(fb.offset(i)) + drmfb = pykms.DmabufFramebuffer(self.card, w, h, fmt, - [fd], [stride], [0]) + fds, strides, offsets) self.cam_2_drm[fb] = drmfb idx += 1 From patchwork Mon May 16 14:10:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 15920 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 2D3C6C3271 for ; Mon, 16 May 2022 14:11:05 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C4A5A65680; Mon, 16 May 2022 16:11:04 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1652710264; bh=MRxE+WJDv6nB+zC5V/SxfwJvigsEeyodx4QT1Xo+d+s=; 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=MTeiA0+iKipv9Wm5jcuqBADuFBjirTEfftZDt+0NBrWFhDy3iye7nrEWRqUsPuWQF Ux0zRy6Fxh+4Hfpidle3BoZ5hkBUK3q2CteHgt5EvJxXP+FM/cm55YG7/oB3FhmbMi TxNdUKzaoXlu8pdw05wbe+tyngu69lhlzBzvvhj5gMpBztDTCdYkNKIwXUYkB4VjQS fsu+pPvpx6N2NopFNr8ZcLL//40rHxIVX4QTimBkeEEBLi+o1oAMetzT/EJTL8GBOE rKcun8P3sg1KKJeg/4381f46UEX02kSg1ETWfFfmUUnkvjb39yMt43CtB27hzMP0xs W8mdvrett2Upg== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 284D765653 for ; Mon, 16 May 2022 16:10:55 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="Qpx2U2Li"; dkim-atps=neutral Received: from deskari.lan (91-156-85-209.elisa-laajakaista.fi [91.156.85.209]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 8E8F98EF; Mon, 16 May 2022 16:10:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1652710254; bh=MRxE+WJDv6nB+zC5V/SxfwJvigsEeyodx4QT1Xo+d+s=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Qpx2U2LiyJ2PlL9K9GCHqE7vZKja8dpr3fQxfB3F4epDjSz/57XZTpTtnufDKMxbB 3ONDOjmQoZ+XM7OrSFQPNXa5zRQpm8AFCmAUvdanvp46KfLgLGVpOyTZpWvcjMrJkw A+JChmClr04DSl4+ni/iGcCp9FQyScn9X5m4jXHs= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Mon, 16 May 2022 17:10:22 +0300 Message-Id: <20220516141022.96327-15-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> References: <20220516141022.96327-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 14/14] py: cam_kms: fix multistream display 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: Tomi Valkeinen via libcamera-devel From: Tomi Valkeinen Reply-To: Tomi Valkeinen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Instead of doing an atomic commit for each stream, do a single commit for the two planes. This fixes the issue that only the first plane was actually shown. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- src/py/cam/cam_kms.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/py/cam/cam_kms.py b/src/py/cam/cam_kms.py index 90aac5f6..74cd3b38 100644 --- a/src/py/cam/cam_kms.py +++ b/src/py/cam/cam_kms.py @@ -67,12 +67,13 @@ class KMSRenderer: buffers = drmreq['camreq'].buffers + req = pykms.AtomicReq(self.card) + for stream, fb in buffers.items(): drmfb = self.cam_2_drm.get(fb, None) - - req = pykms.AtomicReq(self.card) self.add_plane(req, stream, drmfb) - req.commit() + + req.commit() def handle_page_flip(self, frame, time): old = self.current