From patchwork Fri Jul 1 08:45:05 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 16493 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 7D50EBD808 for ; Fri, 1 Jul 2022 08:45:46 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 7FE976564E; Fri, 1 Jul 2022 10:45:43 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1656665143; bh=kAL85UrCX4ZS6H5jh0S4WDQbWuTWODAQW0q+OmJ+1ng=; 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=P+ogX+xQH6TFxAd3rWOBaFnrIR3x4KjzQ/M6dZpnMDqSWnxqB+0SWkrL+Sxy99wew P51PycKRi2G1/ZI6waptUTIaeGpKggKBHcitw4gA4yhwYTibD5Q1Hz76olf1s3vWDu M6ffru9Z7XLLtpB/UoRKslCGtM8RGC0kZ77Sdx6xo2OQWuBO93mtDjWT13jS4Duz+N Hhl5fYtYnB+fFdHmQ00kxeQtZ2Hq+6vd+qNWBubX/uu9Hr0BBHD9+GSR0f8InPQMw9 NFEIwjp9LZ9CipikJ4o8P/4hEkG6MoVbDiBWrnZvu5kk3903/prgwZceP6kgKh0ZvK qB+FVvDWRiBEA== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 69F9D6564B for ; Fri, 1 Jul 2022 10:45:41 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="sjXw6RLy"; dkim-atps=neutral Received: from deskari.lan (91-158-154-79.elisa-laajakaista.fi [91.158.154.79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B20546BB; Fri, 1 Jul 2022 10:45:40 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1656665141; bh=kAL85UrCX4ZS6H5jh0S4WDQbWuTWODAQW0q+OmJ+1ng=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=sjXw6RLya9MXj3WC1tEdKSN5wOdK893QoUKf0ndS7pBZeSIVWX7HgM1xzdHNUWZJ1 etx8BWDDVRCVh17SJuld0u22aZJNVseKhrsddKgYGlpdWcmD0dxJrrrtJd/SMUp6CD fRTJy5XcLRJ6GwZiJRcbIpe0OASt+rzaXiO1Sf60= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Fri, 1 Jul 2022 11:45:05 +0300 Message-Id: <20220701084521.31831-2-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> References: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 01/17] py: cam.py: Fix multi camera capture without -C 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" -C flag is supposed to affect only the camera that was previously defined in the arguments. That's not the case, and, e.g.: cam.py -c2 -C -c3 causes camera 3 to start capturing, but it stops after the initial Requests have been completed. Fix the issue by filtering out camera contexts that do not have -C defined. Signed-off-by: Tomi Valkeinen Reviewed-by: Kieran Bingham Reviewed-by: Laurent Pinchart --- src/py/cam/cam.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/py/cam/cam.py b/src/py/cam/cam.py index 2ae89fa8..8a82e092 100755 --- a/src/py/cam/cam.py +++ b/src/py/cam/cam.py @@ -434,7 +434,10 @@ def main(): if args.info: ctx.do_cmd_info() - if args.capture: + # Filter out capture contexts which are not marked for capture + contexts = [ctx for ctx in contexts if ctx.opt_capture > 0] + + if contexts: state = CaptureState(cm, contexts) if args.renderer == 'null': From patchwork Fri Jul 1 08:45:06 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 16494 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 BAD11BD808 for ; Fri, 1 Jul 2022 08:45:47 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 6CEF765651; Fri, 1 Jul 2022 10:45:44 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1656665144; bh=GApko8Xk7fqa9bcs/6OBQN3OzWVj2WUfL+sa81qKAlw=; 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=sVW57PXTfNsW3NMEFTsnTa5FnZV7fMdIxgREGVojzcKDttL9yLE0ps+edc28N6oEc Jz636YxzTWEGQFZ139vlZnNk4jxvNcDGyio3q51bCNxKihKH/3ZbujYgLpcd/XOjzP HUzWt7RymkSTbxqwb9MZLkJ7vMvNFhjkseR59uwf5F2NIj9n/DkRs7awP90M0asuKM 0C4UzQpBMmWM+dZG0BzbkPRtnKfSJd1tDjTOC/57Wa5o9+mGzx9/35dgZipLBVRKyl TTDioZ1hWJ1eDV9QGF5/eFGHYcSDux1W1NDJnOYui4gt+Piivyg+C1pAOeYnchEuDw oSNDMToYF+dmQ== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id AB1496564E for ; Fri, 1 Jul 2022 10:45:41 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="lipsK3GM"; dkim-atps=neutral Received: from deskari.lan (91-158-154-79.elisa-laajakaista.fi [91.158.154.79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 284DA6D1; Fri, 1 Jul 2022 10:45:41 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1656665141; bh=GApko8Xk7fqa9bcs/6OBQN3OzWVj2WUfL+sa81qKAlw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=lipsK3GMXDr0bEM/DM77KLZPA0AOPrDv11knQUygRjOmrCajWfMlfG9NfwcBdENyq 4yzMBKg5L+/PURWdHkJsiYzLcO69RJwuTSm5k6L9b+c5Zrp3yGOWNhSSHP9S3sPmbS NceESUI5YBKt2L9E7zccti/hF9VSfLqUC1aWUX3E= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Fri, 1 Jul 2022 11:45:06 +0300 Message-Id: <20220701084521.31831-3-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> References: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 02/17] py: Add Python logging category 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 Python logging category, and use it in handleRequestCompleted(). Signed-off-by: Tomi Valkeinen Reviewed-by: Kieran Bingham Reviewed-by: Laurent Pinchart --- src/py/libcamera/py_main.cpp | 12 ++++++++++-- src/py/libcamera/py_main.h | 14 ++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 src/py/libcamera/py_main.h diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp index 505cc3dc..4b698f77 100644 --- a/src/py/libcamera/py_main.cpp +++ b/src/py/libcamera/py_main.cpp @@ -5,6 +5,8 @@ * Python bindings */ +#include "py_main.h" + #include #include #include @@ -23,6 +25,12 @@ namespace py = pybind11; using namespace libcamera; +namespace libcamera { + +LOG_DEFINE_CATEGORY(Python) + +} + template static py::object valueOrTuple(const ControlValue &cv) { @@ -120,10 +128,10 @@ static void handleRequestCompleted(Request *req) size_t s = write(gEventfd, &v, 8); /* * We should never fail, and have no simple means to manage the error, - * so let's use LOG(Fatal). + * so let's log a fatal error. */ if (s != 8) - LOG(Fatal) << "Unable to write to eventfd"; + LOG(Python, Fatal) << "Unable to write to eventfd"; } void init_py_enums(py::module &m); diff --git a/src/py/libcamera/py_main.h b/src/py/libcamera/py_main.h new file mode 100644 index 00000000..5bb5f2d1 --- /dev/null +++ b/src/py/libcamera/py_main.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022, Tomi Valkeinen + */ + +#pragma once + +#include + +namespace libcamera { + +LOG_DECLARE_CATEGORY(Python) + +} From patchwork Fri Jul 1 08:45:07 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 16495 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 DE638BD808 for ; Fri, 1 Jul 2022 08:45:48 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id DE4636565D; Fri, 1 Jul 2022 10:45:44 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1656665144; bh=Pa5/wJaKKF4mEpNi/1FHR/wV42PbNXVxJ/ZFRVOKfAQ=; 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=QcNPgoLyQslVvmyDSiPJuzpb2+VptCBSDyjHlaOMQQEtyIYvojgIetJ+sniCDA11Z KjTgGtLVn8a6JpI9xUzExXC+Ekj9Ty7rasUBiKtSP7RdBnYoA3kX1dbSDLMypAy91Z 5GBWfoZVmonC+RQ1eagyBNyeQU+OMy2G86Hjkt3d0OrKD4dKFIVXR499RQSoaa/8K3 g3jF68JEikp4i9+Epl/D/bH6nZLPdvCEaZ4I2f7D1X/Ba2x0HBxWWCT9TZMJsHTkRO bKUxEIc3pmTtOMI3cTyuBDdF8NFN+Qp1v6hvMqelszTYH8/YIFC7h3Eg16dbbgTV50 BNykKUc97bIRQ== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 262636564E for ; Fri, 1 Jul 2022 10:45:42 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="es+9PqDV"; dkim-atps=neutral Received: from deskari.lan (91-158-154-79.elisa-laajakaista.fi [91.158.154.79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 9892725C; Fri, 1 Jul 2022 10:45:41 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1656665141; bh=Pa5/wJaKKF4mEpNi/1FHR/wV42PbNXVxJ/ZFRVOKfAQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=es+9PqDV+yeP5LR1FoZMw+7ep+4Dqkk3HVgDhV7cqWZ85reFhd+h2Wv6+V3CimB9T I80DVxwQX4K0qsdRXcXo6Wty8szQXa5TVg6znvaYBFZjsV7R8KJu0Eemn6QFKnJoeu 2X5JgIYIpWh0s4vvPD0+AWqS3zAQCXdLkuEWXSaQ= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Fri, 1 Jul 2022 11:45:07 +0300 Message-Id: <20220701084521.31831-4-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> References: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 03/17] py: Move ControlValue helpers to py_helpers.cpp 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" Clean up the py_main.cpp a bit by moving the ControlValue helpers to a separate file. Signed-off-by: Tomi Valkeinen Reviewed-by: Kieran Bingham Reviewed-by: Laurent Pinchart --- src/py/libcamera/meson.build | 1 + src/py/libcamera/py_helpers.cpp | 97 +++++++++++++++++++++++++++++++++ src/py/libcamera/py_helpers.h | 13 +++++ src/py/libcamera/py_main.cpp | 83 +--------------------------- 4 files changed, 113 insertions(+), 81 deletions(-) create mode 100644 src/py/libcamera/py_helpers.cpp create mode 100644 src/py/libcamera/py_helpers.h diff --git a/src/py/libcamera/meson.build b/src/py/libcamera/meson.build index eb884538..04578bac 100644 --- a/src/py/libcamera/meson.build +++ b/src/py/libcamera/meson.build @@ -15,6 +15,7 @@ pybind11_dep = pybind11_proj.get_variable('pybind11_dep') pycamera_sources = files([ 'py_enums.cpp', 'py_geometry.cpp', + 'py_helpers.cpp', 'py_main.cpp', ]) diff --git a/src/py/libcamera/py_helpers.cpp b/src/py/libcamera/py_helpers.cpp new file mode 100644 index 00000000..45aecce9 --- /dev/null +++ b/src/py/libcamera/py_helpers.cpp @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022, Tomi Valkeinen + */ + +#include "py_helpers.h" + +#include + +#include +#include +#include + +namespace py = pybind11; + +using namespace libcamera; + +template +static py::object valueOrTuple(const ControlValue &cv) +{ + if (cv.isArray()) { + const T *v = reinterpret_cast(cv.data().data()); + auto t = py::tuple(cv.numElements()); + + for (size_t i = 0; i < cv.numElements(); ++i) + t[i] = v[i]; + + return std::move(t); + } + + return py::cast(cv.get()); +} + +py::object controlValueToPy(const ControlValue &cv) +{ + switch (cv.type()) { + case ControlTypeBool: + return valueOrTuple(cv); + case ControlTypeByte: + return valueOrTuple(cv); + case ControlTypeInteger32: + return valueOrTuple(cv); + case ControlTypeInteger64: + return valueOrTuple(cv); + case ControlTypeFloat: + return valueOrTuple(cv); + case ControlTypeString: + return py::cast(cv.get()); + case ControlTypeRectangle: { + const Rectangle *v = reinterpret_cast(cv.data().data()); + return py::cast(v); + } + case ControlTypeSize: { + const Size *v = reinterpret_cast(cv.data().data()); + return py::cast(v); + } + case ControlTypeNone: + default: + throw std::runtime_error("Unsupported ControlValue type"); + } +} + +template +static ControlValue controlValueMaybeArray(const py::object &ob) +{ + if (py::isinstance(ob) || py::isinstance(ob)) { + std::vector vec = ob.cast>(); + return ControlValue(Span(vec)); + } + + return ControlValue(ob.cast()); +} + +ControlValue pyToControlValue(const py::object &ob, ControlType type) +{ + switch (type) { + case ControlTypeBool: + return ControlValue(ob.cast()); + case ControlTypeByte: + return controlValueMaybeArray(ob); + case ControlTypeInteger32: + return controlValueMaybeArray(ob); + case ControlTypeInteger64: + return controlValueMaybeArray(ob); + case ControlTypeFloat: + return controlValueMaybeArray(ob); + case ControlTypeString: + return ControlValue(ob.cast()); + case ControlTypeRectangle: + return ControlValue(ob.cast()); + case ControlTypeSize: + return ControlValue(ob.cast()); + case ControlTypeNone: + default: + throw std::runtime_error("Control type not implemented"); + } +} diff --git a/src/py/libcamera/py_helpers.h b/src/py/libcamera/py_helpers.h new file mode 100644 index 00000000..cd31e2cc --- /dev/null +++ b/src/py/libcamera/py_helpers.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022, Tomi Valkeinen + */ + +#pragma once + +#include + +#include + +pybind11::object controlValueToPy(const libcamera::ControlValue &cv); +libcamera::ControlValue pyToControlValue(const pybind11::object &ob, libcamera::ControlType type); diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp index 4b698f77..e652837f 100644 --- a/src/py/libcamera/py_main.cpp +++ b/src/py/libcamera/py_main.cpp @@ -21,6 +21,8 @@ #include #include +#include "py_helpers.h" + namespace py = pybind11; using namespace libcamera; @@ -31,87 +33,6 @@ LOG_DEFINE_CATEGORY(Python) } -template -static py::object valueOrTuple(const ControlValue &cv) -{ - if (cv.isArray()) { - const T *v = reinterpret_cast(cv.data().data()); - auto t = py::tuple(cv.numElements()); - - for (size_t i = 0; i < cv.numElements(); ++i) - t[i] = v[i]; - - return std::move(t); - } - - return py::cast(cv.get()); -} - -static py::object controlValueToPy(const ControlValue &cv) -{ - switch (cv.type()) { - case ControlTypeBool: - return valueOrTuple(cv); - case ControlTypeByte: - return valueOrTuple(cv); - case ControlTypeInteger32: - return valueOrTuple(cv); - case ControlTypeInteger64: - return valueOrTuple(cv); - case ControlTypeFloat: - return valueOrTuple(cv); - case ControlTypeString: - return py::cast(cv.get()); - case ControlTypeRectangle: { - const Rectangle *v = reinterpret_cast(cv.data().data()); - return py::cast(v); - } - case ControlTypeSize: { - const Size *v = reinterpret_cast(cv.data().data()); - return py::cast(v); - } - case ControlTypeNone: - default: - throw std::runtime_error("Unsupported ControlValue type"); - } -} - -template -static ControlValue controlValueMaybeArray(const py::object &ob) -{ - if (py::isinstance(ob) || py::isinstance(ob)) { - std::vector vec = ob.cast>(); - return ControlValue(Span(vec)); - } - - return ControlValue(ob.cast()); -} - -static ControlValue pyToControlValue(const py::object &ob, ControlType type) -{ - switch (type) { - case ControlTypeBool: - return ControlValue(ob.cast()); - case ControlTypeByte: - return controlValueMaybeArray(ob); - case ControlTypeInteger32: - return controlValueMaybeArray(ob); - case ControlTypeInteger64: - return controlValueMaybeArray(ob); - case ControlTypeFloat: - return controlValueMaybeArray(ob); - case ControlTypeString: - return ControlValue(ob.cast()); - case ControlTypeRectangle: - return ControlValue(ob.cast()); - case ControlTypeSize: - return ControlValue(ob.cast()); - case ControlTypeNone: - default: - throw std::runtime_error("Control type not implemented"); - } -} - static std::weak_ptr gCameraManager; static int gEventfd; static std::mutex gReqlistMutex; From patchwork Fri Jul 1 08:45:08 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 16496 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 C88E8BD808 for ; Fri, 1 Jul 2022 08:45:49 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 636CE65653; Fri, 1 Jul 2022 10:45:45 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1656665145; bh=fsW6BoODeR+MuGUOJjRgSvniGg9SQ+z5nws1Simatns=; 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=i9M2awn5rPWbWF0Bxf51Hky0au3P3Y9jdhtoMLOI/45ezaeHVWcm6l3cF9qgNNoAU KVWB1PHK4QWMWUil6KbfwFXo5McH5Avc+8c9KX9tmLifxW0ZqPs+n99M0W4mQAvC5l a636wR/ETRZ7z0GbgXVKxDnciB5++kTJtIx7An/LF2ospBZfJXmOLWs1CDYAMNaaNY YGjsvrjXzTK28HpTASxoW7fjevhU5/lMsY7Q0wHuNpuHzvacfoQb5bXdbHu73EImIY /+MuS/B6BL7zKgjbiDrGGequFzat6vD3oK9vcTIVQfy8q0psj+WPUowIlFmiWo6EKK 7qaXDsN85waWA== 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 9C67B6564F for ; Fri, 1 Jul 2022 10:45:42 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="bVa3bdcc"; dkim-atps=neutral Received: from deskari.lan (91-158-154-79.elisa-laajakaista.fi [91.158.154.79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 13C2F6BB; Fri, 1 Jul 2022 10:45:42 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1656665142; bh=fsW6BoODeR+MuGUOJjRgSvniGg9SQ+z5nws1Simatns=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bVa3bdccLStUWk04TKhjoEKbHq4EinO1UyKHbTab9owAgUW96qeif1VBRxhUcHoQk +LRCXDpArzDZE0GTpyAW+yG8sbh0dRsuvWMDbqHcTP8riI1TN+a2t/DadSJqrzTCxY RbJgSGvcHPDLAvYxajBMtrlq3/6rvjZ3n6uuvH0U= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Fri, 1 Jul 2022 11:45:08 +0300 Message-Id: <20220701084521.31831-5-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> References: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 04/17] py: cam.py: Remove todo comment 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" The comment is no longer valid. Signed-off-by: Tomi Valkeinen Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/py/cam/cam.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/py/cam/cam.py b/src/py/cam/cam.py index 8a82e092..2701d937 100755 --- a/src/py/cam/cam.py +++ b/src/py/cam/cam.py @@ -3,9 +3,6 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (C) 2022, Tomi Valkeinen -# \todo Convert ctx and state dicts to proper classes, and move relevant -# functions to those classes. - from typing import Any import argparse import binascii From patchwork Fri Jul 1 08:45: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: 16497 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 76322BD808 for ; Fri, 1 Jul 2022 08:45:50 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id EB0356569E; Fri, 1 Jul 2022 10:45:47 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1656665148; bh=FDESrgPL0gxNa+Z4XsJ2JAUY5xvJcK9lZM+SU5xx8Xw=; 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=RmbNu61OLccvlsqaXnSr6GyRr/X5PG/ESM/eXTwpjrmwobimEP7X/mSDqY+8pOmIx J+LZFE+upUnh2aejxcEb3JJZUQeZacs1sRalG1kw7uRRlUwe4lhvtDrp7yAMDl4oS2 9WkwnkLI4ONCvSUTr9L4aOTVolAV4GffGSQsKqnnVGCtCGuSv9TsvsebT4yFr1hF0L j/SmspIygeBPtCWBFzH7+6OOMacl1i3ujo2Vl8BM253ipqzTgEobV+1F/XF6+WvIlp j5V2zKDOAeu5YUIYELiE1ZSGjuSseYLovgS7gqhP8gWqfUzfDVn8bk6G0U4wWd+IbL +KZMyuN/x7LuQ== 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 34D2465657 for ; Fri, 1 Jul 2022 10:45:43 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="mRLyU1a9"; dkim-atps=neutral Received: from deskari.lan (91-158-154-79.elisa-laajakaista.fi [91.158.154.79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 8B8F625C; Fri, 1 Jul 2022 10:45:42 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1656665142; bh=FDESrgPL0gxNa+Z4XsJ2JAUY5xvJcK9lZM+SU5xx8Xw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mRLyU1a9/+aZjyNAIcH+VbVzopNsoOOLYt+poXwXViQswfw/5mJj0+GkFKCwknSWj WIz9VTCx6Sj5u/I1hs0LzQ9+VGjrHWfDwWUH+ki/CH+Fu//cMmeZZbgSt//e1iBcpi KYBGORLCTpGkWvO0T+RgxDthYWTpkSc5fA9DrYlo= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Fri, 1 Jul 2022 11:45:09 +0300 Message-Id: <20220701084521.31831-6-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> References: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 05/17] py: Create PyCameraManager 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" Wrap the CameraManager with a PyCameraManager class and move the related code inside the new class. This helps understanding the life times of the used-to-be global variables, gets rid of static handleRequestCompleted function, and allows us to simplify the binding code as the more complex pieces are inside the class. There should be no user visible functional changes. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- src/py/libcamera/meson.build | 1 + src/py/libcamera/py_camera_manager.cpp | 125 +++++++++++++++++++++++++ src/py/libcamera/py_camera_manager.h | 44 +++++++++ src/py/libcamera/py_main.cpp | 117 +++++------------------ 4 files changed, 193 insertions(+), 94 deletions(-) create mode 100644 src/py/libcamera/py_camera_manager.cpp create mode 100644 src/py/libcamera/py_camera_manager.h diff --git a/src/py/libcamera/meson.build b/src/py/libcamera/meson.build index 04578bac..ad2a6858 100644 --- a/src/py/libcamera/meson.build +++ b/src/py/libcamera/meson.build @@ -13,6 +13,7 @@ pybind11_proj = subproject('pybind11') pybind11_dep = pybind11_proj.get_variable('pybind11_dep') pycamera_sources = files([ + 'py_camera_manager.cpp', 'py_enums.cpp', 'py_geometry.cpp', 'py_helpers.cpp', diff --git a/src/py/libcamera/py_camera_manager.cpp b/src/py/libcamera/py_camera_manager.cpp new file mode 100644 index 00000000..ad47271d --- /dev/null +++ b/src/py/libcamera/py_camera_manager.cpp @@ -0,0 +1,125 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022, Tomi Valkeinen + */ + +#include "py_camera_manager.h" + +#include +#include +#include +#include + +#include "py_main.h" + +namespace py = pybind11; + +using namespace libcamera; + +PyCameraManager::PyCameraManager() +{ + LOG(Python, Debug) << "PyCameraManager()"; + + cameraManager_ = std::make_unique(); + + int fd = eventfd(0, 0); + if (fd == -1) + throw std::system_error(errno, std::generic_category(), + "Failed to create eventfd"); + + eventFd_ = fd; + + int ret = cameraManager_->start(); + if (ret) { + close(fd); + eventFd_ = -1; + throw std::system_error(-ret, std::generic_category(), + "Failed to start CameraManager"); + } +} + +PyCameraManager::~PyCameraManager() +{ + LOG(Python, Debug) << "~PyCameraManager()"; + + if (eventFd_ != -1) { + close(eventFd_); + eventFd_ = -1; + } +} + +py::list PyCameraManager::cameras() +{ + /* + * Create a list of Cameras, where each camera has a keep-alive to + * CameraManager. + */ + py::list l; + + for (auto &camera : cameraManager_->cameras()) { + py::object py_cm = py::cast(this); + py::object py_cam = py::cast(camera); + py::detail::keep_alive_impl(py_cam, py_cm); + l.append(py_cam); + } + + return l; +} + +std::vector PyCameraManager::getReadyRequests() +{ + readFd(); + + std::vector ret; + + for (Request *request : getCompletedRequests()) { + py::object o = py::cast(request); + /* Decrease the ref increased in Camera.queue_request() */ + o.dec_ref(); + ret.push_back(o); + } + + return ret; +} + +/* Note: Called from another thread */ +void PyCameraManager::handleRequestCompleted(Request *req) +{ + pushRequest(req); + writeFd(); +} + +void PyCameraManager::writeFd() +{ + uint64_t v = 1; + + size_t s = write(eventFd_, &v, 8); + /* + * We should never fail, and have no simple means to manage the error, + * so let's log a fatal error. + */ + if (s != 8) + LOG(Python, Fatal) << "Unable to write to eventfd"; +} + +void PyCameraManager::readFd() +{ + uint8_t buf[8]; + + if (read(eventFd_, buf, 8) != 8) + throw std::system_error(errno, std::generic_category()); +} + +void PyCameraManager::pushRequest(Request *req) +{ + std::lock_guard guard(completedRequestsMutex_); + completedRequests_.push_back(req); +} + +std::vector PyCameraManager::getCompletedRequests() +{ + std::vector v; + std::lock_guard guard(completedRequestsMutex_); + swap(v, completedRequests_); + return v; +} diff --git a/src/py/libcamera/py_camera_manager.h b/src/py/libcamera/py_camera_manager.h new file mode 100644 index 00000000..9c15f814 --- /dev/null +++ b/src/py/libcamera/py_camera_manager.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2022, Tomi Valkeinen + */ + +#pragma once + +#include + +#include + +#include + +using namespace libcamera; + +class PyCameraManager +{ +public: + PyCameraManager(); + ~PyCameraManager(); + + pybind11::list cameras(); + std::shared_ptr get(const std::string &name) { return cameraManager_->get(name); } + + static const std::string &version() { return CameraManager::version(); } + + int eventFd() const { return eventFd_; } + + std::vector getReadyRequests(); + + void handleRequestCompleted(Request *req); + +private: + std::unique_ptr cameraManager_; + + int eventFd_ = -1; + std::mutex completedRequestsMutex_; + std::vector completedRequests_; + + void writeFd(); + void readFd(); + void pushRequest(Request *req); + std::vector getCompletedRequests(); +}; diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp index e652837f..e7d078b5 100644 --- a/src/py/libcamera/py_main.cpp +++ b/src/py/libcamera/py_main.cpp @@ -7,10 +7,7 @@ #include "py_main.h" -#include #include -#include -#include #include @@ -21,6 +18,7 @@ #include #include +#include "py_camera_manager.h" #include "py_helpers.h" namespace py = pybind11; @@ -33,27 +31,11 @@ LOG_DEFINE_CATEGORY(Python) } -static std::weak_ptr gCameraManager; -static int gEventfd; -static std::mutex gReqlistMutex; -static std::vector gReqList; - -static void handleRequestCompleted(Request *req) -{ - { - std::lock_guard guard(gReqlistMutex); - gReqList.push_back(req); - } - - uint64_t v = 1; - size_t s = write(gEventfd, &v, 8); - /* - * We should never fail, and have no simple means to manage the error, - * so let's log a fatal error. - */ - if (s != 8) - LOG(Python, Fatal) << "Unable to write to eventfd"; -} +/* + * Note: global C++ destructors can be ran on this before the py module is + * destructed. + */ +static std::weak_ptr gCameraManager; void init_py_enums(py::module &m); void init_py_controls_generated(py::module &m); @@ -76,7 +58,7 @@ PYBIND11_MODULE(_libcamera, m) * https://pybind11.readthedocs.io/en/latest/advanced/misc.html#avoiding-c-types-in-docstrings */ - auto pyCameraManager = py::class_(m, "CameraManager"); + auto pyCameraManager = py::class_(m, "CameraManager"); auto pyCamera = py::class_(m, "Camera"); auto pyCameraConfiguration = py::class_(m, "CameraConfiguration"); auto pyCameraConfigurationStatus = py::enum_(pyCameraConfiguration, "Status"); @@ -110,78 +92,22 @@ PYBIND11_MODULE(_libcamera, m) /* Classes */ pyCameraManager .def_static("singleton", []() { - std::shared_ptr cm = gCameraManager.lock(); - if (cm) - return cm; - - int fd = eventfd(0, 0); - if (fd == -1) - throw std::system_error(errno, std::generic_category(), - "Failed to create eventfd"); - - cm = std::shared_ptr(new CameraManager, [](auto p) { - close(gEventfd); - gEventfd = -1; - delete p; - }); - - gEventfd = fd; - gCameraManager = cm; - - int ret = cm->start(); - if (ret) - throw std::system_error(-ret, std::generic_category(), - "Failed to start CameraManager"); - - return cm; - }) - - .def_property_readonly("version", &CameraManager::version) + std::shared_ptr cm = gCameraManager.lock(); - .def_property_readonly("event_fd", [](CameraManager &) { - return gEventfd; - }) - - .def("get_ready_requests", [](CameraManager &) { - uint8_t buf[8]; - - if (read(gEventfd, buf, 8) != 8) - throw std::system_error(errno, std::generic_category()); - - std::vector v; - - { - std::lock_guard guard(gReqlistMutex); - swap(v, gReqList); + if (!cm) { + cm = std::make_shared(); + gCameraManager = cm; } - std::vector ret; - - for (Request *req : v) { - py::object o = py::cast(req); - /* Decrease the ref increased in Camera.queue_request() */ - o.dec_ref(); - ret.push_back(o); - } - - return ret; + return cm; }) - .def("get", py::overload_cast(&CameraManager::get), py::keep_alive<0, 1>()) - - /* Create a list of Cameras, where each camera has a keep-alive to CameraManager */ - .def_property_readonly("cameras", [](CameraManager &self) { - py::list l; - - for (auto &c : self.cameras()) { - py::object py_cm = py::cast(self); - py::object py_cam = py::cast(c); - py::detail::keep_alive_impl(py_cam, py_cm); - l.append(py_cam); - } + .def_property_readonly("version", &PyCameraManager::version) + .def("get", &PyCameraManager::get, py::keep_alive<0, 1>()) + .def_property_readonly("cameras", &PyCameraManager::cameras) - return l; - }); + .def_property_readonly("event_fd", &PyCameraManager::eventFd) + .def("get_ready_requests", &PyCameraManager::getReadyRequests); pyCamera .def_property_readonly("id", &Camera::id) @@ -191,7 +117,10 @@ PYBIND11_MODULE(_libcamera, m) const std::unordered_map &controls) { /* \todo What happens if someone calls start() multiple times? */ - self.requestCompleted.connect(handleRequestCompleted); + auto cm = gCameraManager.lock(); + ASSERT(cm); + + self.requestCompleted.connect(cm.get(), &PyCameraManager::handleRequestCompleted); ControlList controlList(self.controls()); @@ -202,7 +131,7 @@ PYBIND11_MODULE(_libcamera, m) int ret = self.start(&controlList); if (ret) { - self.requestCompleted.disconnect(handleRequestCompleted); + self.requestCompleted.disconnect(); return ret; } @@ -214,7 +143,7 @@ PYBIND11_MODULE(_libcamera, m) if (ret) return ret; - self.requestCompleted.disconnect(handleRequestCompleted); + self.requestCompleted.disconnect(); return 0; }) From patchwork Fri Jul 1 08:45: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: 16498 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 34159BD808 for ; Fri, 1 Jul 2022 08:45:51 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0E797656A0; Fri, 1 Jul 2022 10:45:49 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1656665149; bh=eCXWxXuGWl5r0HMuik1XEkAxHOfVyvYcsHvaM+5SdA8=; 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=VtovqRHEcuk4ESMfuviee5cLgHvkOFbMXGgFwu+O+7IxbPcNarytq7dNWVK2130uA wWe/nwahd1gGESfxrq2LF/w7DTXCNH9dtOCulZutrbf0JtGMTAzmSmedCViX9NPTX7 8B5txjtSkTxlC2RRC7ESCf7wqfSEcLfLQOT4hSr4PjNlsZyXJxG1hnTCCu2/7+f0la x93+lh6DGbGEHwZnG5D14ZieLwJ/x3P653nDXCu5FPxWL6zVDARESz30B31vcF76Wi bV8pUR4fPqfGfn0YiWXm0/h+K6cxwPvp+z1J/lmO5bGsiz+pjMDKMzjH40sOFb7Lhr PlxFqGbnUZUcA== 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 85ECA65654 for ; Fri, 1 Jul 2022 10:45:43 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="ckX+jhBv"; dkim-atps=neutral Received: from deskari.lan (91-158-154-79.elisa-laajakaista.fi [91.158.154.79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 02C8B6D1; Fri, 1 Jul 2022 10:45:42 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1656665143; bh=eCXWxXuGWl5r0HMuik1XEkAxHOfVyvYcsHvaM+5SdA8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ckX+jhBvtLeNHwfUAHxwqfRi/HxivTisDLLD2PMceSHQwRGOZtW8p1ulPYT/qlgcv Ju2Ke3mG6Fa2siAQBHuwb7KBe6Ubx/+9v3Sk2vP4j+hBgQC4wE96kbF2uv1P86DGvK 3FurkPDYAFeggwJnxMb4lU+pgafTfNHXuIE9dcto= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Fri, 1 Jul 2022 11:45:10 +0300 Message-Id: <20220701084521.31831-7-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> References: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 06/17] py: Use UniqueFD 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" Use UniqueFD to automate the eventfd lifetime management. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- src/py/libcamera/py_camera_manager.cpp | 16 ++++------------ src/py/libcamera/py_camera_manager.h | 4 ++-- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/py/libcamera/py_camera_manager.cpp b/src/py/libcamera/py_camera_manager.cpp index ad47271d..51a890c8 100644 --- a/src/py/libcamera/py_camera_manager.cpp +++ b/src/py/libcamera/py_camera_manager.cpp @@ -27,25 +27,17 @@ PyCameraManager::PyCameraManager() throw std::system_error(errno, std::generic_category(), "Failed to create eventfd"); - eventFd_ = fd; + eventFd_ = UniqueFD(fd); int ret = cameraManager_->start(); - if (ret) { - close(fd); - eventFd_ = -1; + if (ret) throw std::system_error(-ret, std::generic_category(), "Failed to start CameraManager"); - } } PyCameraManager::~PyCameraManager() { LOG(Python, Debug) << "~PyCameraManager()"; - - if (eventFd_ != -1) { - close(eventFd_); - eventFd_ = -1; - } } py::list PyCameraManager::cameras() @@ -93,7 +85,7 @@ void PyCameraManager::writeFd() { uint64_t v = 1; - size_t s = write(eventFd_, &v, 8); + size_t s = write(eventFd_.get(), &v, 8); /* * We should never fail, and have no simple means to manage the error, * so let's log a fatal error. @@ -106,7 +98,7 @@ void PyCameraManager::readFd() { uint8_t buf[8]; - if (read(eventFd_, buf, 8) != 8) + if (read(eventFd_.get(), buf, 8) != 8) throw std::system_error(errno, std::generic_category()); } diff --git a/src/py/libcamera/py_camera_manager.h b/src/py/libcamera/py_camera_manager.h index 9c15f814..710163e8 100644 --- a/src/py/libcamera/py_camera_manager.h +++ b/src/py/libcamera/py_camera_manager.h @@ -24,7 +24,7 @@ public: static const std::string &version() { return CameraManager::version(); } - int eventFd() const { return eventFd_; } + int eventFd() const { return eventFd_.get(); } std::vector getReadyRequests(); @@ -33,7 +33,7 @@ public: private: std::unique_ptr cameraManager_; - int eventFd_ = -1; + UniqueFD eventFd_; std::mutex completedRequestsMutex_; std::vector completedRequests_; From patchwork Fri Jul 1 08:45: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: 16499 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 DEFD3BD808 for ; Fri, 1 Jul 2022 08:45:51 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id BDE1765662; Fri, 1 Jul 2022 10:45:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1656665151; bh=4jssbuxUq5C1GVY59JXBlIIcwKau4KEUhfDWEvwAuHc=; 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=zNJtsdU3luPxDfdTCVNynzzZSCzkq54Xw6/WnxnLgHfeIrwnzGyA2Zry8avA2P3ja 7XdOYbD/1qJbrx/Ty//6S5wzr8iSXy8MMFuAip8xhKxhmgznvrxgvDR3+zbNAwbeOh oduZiTcbJf+UhxDE8+f14rQy/S8wC0+ojPVUkaHKLaTIg8ywY7WwJHP92Ip4437BL1 GxiscMTQKwmpqWOMRP/Q/NU5/6H1dNNNt3GtoMSHuLzkLoDRTHWhFMflj4Pym8r6Hg dVLhCYLr4C88h+Ovk7pRauFN6JahW0xoaPaH2h6pEYSzzQA/FolUchSGuJK8nLxO7w URbbIuLAJMj1w== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0A52265659 for ; Fri, 1 Jul 2022 10:45:44 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="L5aYaAx9"; dkim-atps=neutral Received: from deskari.lan (91-158-154-79.elisa-laajakaista.fi [91.158.154.79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 710DF25C; Fri, 1 Jul 2022 10:45:43 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1656665143; bh=4jssbuxUq5C1GVY59JXBlIIcwKau4KEUhfDWEvwAuHc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=L5aYaAx9Q2T+ChYL315NXL8Ki06PTyUCKsKuV8NvT6amCKfsotOxlkByvXuYTF4/Y Hu+rfMTo6TSe0XWzledVtEwygt1LMIEH+cDLJ5sobKfHT2XO9wEt0KSUBepymUDIGa rFbcQgG6CyxuXN0ltmzRIZDOPmTqzOzwtpiWORH0= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Fri, 1 Jul 2022 11:45:11 +0300 Message-Id: <20220701084521.31831-8-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> References: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 07/17] py: Set EFD_CLOEXEC on eventfd to avoid fd leaking 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" Set EFD_CLOEXEC on eventfd to avoid fd leaking. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- src/py/libcamera/py_camera_manager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/py/libcamera/py_camera_manager.cpp b/src/py/libcamera/py_camera_manager.cpp index 51a890c8..3d422c9e 100644 --- a/src/py/libcamera/py_camera_manager.cpp +++ b/src/py/libcamera/py_camera_manager.cpp @@ -22,7 +22,7 @@ PyCameraManager::PyCameraManager() cameraManager_ = std::make_unique(); - int fd = eventfd(0, 0); + int fd = eventfd(0, EFD_CLOEXEC); if (fd == -1) throw std::system_error(errno, std::generic_category(), "Failed to create eventfd"); From patchwork Fri Jul 1 08:45: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: 16500 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 82DFEBD808 for ; Fri, 1 Jul 2022 08:45:52 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 96EF7656A2; Fri, 1 Jul 2022 10:45:51 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1656665151; bh=P4csJrs78yKiXsTsTozO9b8oqqTGp+igSSWlBlKQZyo=; 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=2/vUu7/DC0dhRkaIqLBHftWYN4YhKCy+vB5rUbdDVUcKZLb1Rt0FQBog2ShAZBRH5 qRYJXq0mS+wtfdQaIA9mEkrECxhm9sGkqJ4vIgopCKXMm/khx8vG7z2Q6mSS5t6MGv JyiS6kcV8ql3z4+ooatG0/crQmCA5y8oo65Lke6gQ0UyvFHlfPlp88AcJnSb1F31sn wnCHwchtll3Sq6GExTC1F0l8nZvFpVzyE6cCuyz9K/97ngTnEokjHPDRK8RFimV1eC LooZSw9aXwDcxjHdk0c2wq7yyOczh4baZ+ssjC05SJP21R/2mmF5XVLPkO85ZZTOSr h6yMT6Yk7hykg== 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 706146565A for ; Fri, 1 Jul 2022 10:45:44 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="E8M8d94Y"; dkim-atps=neutral Received: from deskari.lan (91-158-154-79.elisa-laajakaista.fi [91.158.154.79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E93C46BB; Fri, 1 Jul 2022 10:45:43 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1656665144; bh=P4csJrs78yKiXsTsTozO9b8oqqTGp+igSSWlBlKQZyo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=E8M8d94Y67VIBIDmTdeXp8JqrhS8qibWJZTqUODEDjLHDGg/gs67R7d0hUYpAbY9F gLCQqBzdHwNwb+838+HoMf5cDN+LHg5HXD6WqU3N6oEMFf1AZ2hrRTAzktAudyGG4j BUxW9LHcLVx7oLbTDH3p8OMXUgWWz+drRnvBxyX8= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Fri, 1 Jul 2022 11:45:12 +0300 Message-Id: <20220701084521.31831-9-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> References: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 08/17] py: Use libcamera's Mutex 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" Use libcamera's Mutex and MutexLocker instead of the std versions to get thread safety annotations. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- src/py/libcamera/py_camera_manager.cpp | 4 ++-- src/py/libcamera/py_camera_manager.h | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/py/libcamera/py_camera_manager.cpp b/src/py/libcamera/py_camera_manager.cpp index 3d422c9e..5600f661 100644 --- a/src/py/libcamera/py_camera_manager.cpp +++ b/src/py/libcamera/py_camera_manager.cpp @@ -104,14 +104,14 @@ void PyCameraManager::readFd() void PyCameraManager::pushRequest(Request *req) { - std::lock_guard guard(completedRequestsMutex_); + MutexLocker guard(completedRequestsMutex_); completedRequests_.push_back(req); } std::vector PyCameraManager::getCompletedRequests() { std::vector v; - std::lock_guard guard(completedRequestsMutex_); + MutexLocker guard(completedRequestsMutex_); swap(v, completedRequests_); return v; } diff --git a/src/py/libcamera/py_camera_manager.h b/src/py/libcamera/py_camera_manager.h index 710163e8..56bea13d 100644 --- a/src/py/libcamera/py_camera_manager.h +++ b/src/py/libcamera/py_camera_manager.h @@ -5,7 +5,7 @@ #pragma once -#include +#include #include @@ -34,8 +34,9 @@ private: std::unique_ptr cameraManager_; UniqueFD eventFd_; - std::mutex completedRequestsMutex_; - std::vector completedRequests_; + libcamera::Mutex completedRequestsMutex_; + std::vector completedRequests_ + LIBCAMERA_TSA_GUARDED_BY(completedRequestsMutex_); void writeFd(); void readFd(); From patchwork Fri Jul 1 08:45: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: 16501 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 1D934BD808 for ; Fri, 1 Jul 2022 08:45:53 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 595F7656A6; Fri, 1 Jul 2022 10:45:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1656665152; bh=t3z1boBAErV4KT5ni+tiw18/p6GL+055t+oTd6lKo60=; 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=OWNNLFPnVGspMGFHjZqSAlfXI2L6jscIdndblp/erm2S82IYo0FYnpITOBSSqYJ97 +V+9UydUxf1AZysvxY9VyHwiyetfeWXhk/JsLAon7KprEQVtupegZXJbrXTSwVFAww inDIfN39sywjs2twuRV5NifxMZgyysaMUUF/sAon+/Rz8SKwJUhuP6smBEOVOs3eK9 QFY9S48XFQj7MonqLX7tbJCulqBdjdKSNz4BHSAwV0LmZJRLqGjnaPpPgWq4QmYFxQ yKfvt+A6Dp5+dYMDAPEuTXpdxaI26byurk1pVNAZd177WzhWMkC4hTMYl71dkYy6Di LG6nwn661IPog== 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 E0B6D6565E for ; Fri, 1 Jul 2022 10:45:44 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="LgmvwpaH"; dkim-atps=neutral Received: from deskari.lan (91-158-154-79.elisa-laajakaista.fi [91.158.154.79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 5EC8325C; Fri, 1 Jul 2022 10:45:44 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1656665144; bh=t3z1boBAErV4KT5ni+tiw18/p6GL+055t+oTd6lKo60=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=LgmvwpaHqfkOnk9nD8c7/fy6NAfJKKwdoIttKomG40Bo89pTpvx8pESxVsvQhM/jz nS5KqkQW6uq+YjmqodsFHSksQ+ALtKCfUx9aNdOpFXCrNuZ+rIAvwBBsl1k7iS7IBe aMrFxmoIy3VBjhBN6mFC640erznRH4DGoi/nr8xw= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Fri, 1 Jul 2022 11:45:13 +0300 Message-Id: <20220701084521.31831-10-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> References: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 09/17] py: Switch to non-blocking eventfd 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" Blocking wait can be easily implemented on top in Python, so rather than supporting only blocking reads, or supporting both non-blocking and blocking reads, let's support only non-blocking reads. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- src/py/examples/simple-cam.py | 5 +++-- src/py/examples/simple-capture.py | 12 +++++++++-- src/py/examples/simple-continuous-capture.py | 5 +++-- src/py/libcamera/py_camera_manager.cpp | 22 +++++++++++++------- src/py/libcamera/py_camera_manager.h | 2 +- test/py/unittests.py | 7 +++++++ 6 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/py/examples/simple-cam.py b/src/py/examples/simple-cam.py index 2b81bb65..b3e97ca7 100755 --- a/src/py/examples/simple-cam.py +++ b/src/py/examples/simple-cam.py @@ -19,8 +19,9 @@ TIMEOUT_SEC = 3 def handle_camera_event(cm): - # cm.get_ready_requests() will not block here, as we know there is an event - # to read. + # cm.get_ready_requests() returns the ready requests, which in our case + # should almost always return a single Request, but in some cases there + # could be multiple or none. reqs = cm.get_ready_requests() diff --git a/src/py/examples/simple-capture.py b/src/py/examples/simple-capture.py index a6a9b33e..5f93574f 100755 --- a/src/py/examples/simple-capture.py +++ b/src/py/examples/simple-capture.py @@ -14,6 +14,7 @@ import argparse import libcamera as libcam +import selectors import sys # Number of frames to capture @@ -107,11 +108,18 @@ def main(): # The main loop. Wait for the queued Requests to complete, process them, # and re-queue them again. + sel = selectors.DefaultSelector() + sel.register(cm.event_fd, selectors.EVENT_READ) + while frames_done < TOTAL_FRAMES: - # cm.get_ready_requests() blocks until there is an event and returns - # all the ready requests. Here we should almost always get a single + # cm.get_ready_requests() does not block, so we use a Selector to wait + # for a camera event. Here we should almost always get a single # Request, but in some cases there could be multiple or none. + events = sel.select() + if not events: + continue + reqs = cm.get_ready_requests() for req in reqs: diff --git a/src/py/examples/simple-continuous-capture.py b/src/py/examples/simple-continuous-capture.py index fe78a2dd..26a8060b 100755 --- a/src/py/examples/simple-continuous-capture.py +++ b/src/py/examples/simple-continuous-capture.py @@ -88,8 +88,9 @@ class CaptureContext: camera_contexts: list[CameraCaptureContext] = [] def handle_camera_event(self): - # cm.get_ready_requests() will not block here, as we know there is an event - # to read. + # cm.get_ready_requests() returns the ready requests, which in our case + # should almost always return a single Request, but in some cases there + # could be multiple or none. reqs = self.cm.get_ready_requests() diff --git a/src/py/libcamera/py_camera_manager.cpp b/src/py/libcamera/py_camera_manager.cpp index 5600f661..3dd8668e 100644 --- a/src/py/libcamera/py_camera_manager.cpp +++ b/src/py/libcamera/py_camera_manager.cpp @@ -22,7 +22,7 @@ PyCameraManager::PyCameraManager() cameraManager_ = std::make_unique(); - int fd = eventfd(0, EFD_CLOEXEC); + int fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); if (fd == -1) throw std::system_error(errno, std::generic_category(), "Failed to create eventfd"); @@ -60,18 +60,24 @@ py::list PyCameraManager::cameras() std::vector PyCameraManager::getReadyRequests() { - readFd(); + int ret = readFd(); - std::vector ret; + if (ret == EAGAIN) + return std::vector(); + + if (ret != 0) + throw std::system_error(ret, std::generic_category()); + + std::vector py_reqs; for (Request *request : getCompletedRequests()) { py::object o = py::cast(request); /* Decrease the ref increased in Camera.queue_request() */ o.dec_ref(); - ret.push_back(o); + py_reqs.push_back(o); } - return ret; + return py_reqs; } /* Note: Called from another thread */ @@ -94,12 +100,14 @@ void PyCameraManager::writeFd() LOG(Python, Fatal) << "Unable to write to eventfd"; } -void PyCameraManager::readFd() +int PyCameraManager::readFd() { uint8_t buf[8]; if (read(eventFd_.get(), buf, 8) != 8) - throw std::system_error(errno, std::generic_category()); + return errno; + + return 0; } void PyCameraManager::pushRequest(Request *req) diff --git a/src/py/libcamera/py_camera_manager.h b/src/py/libcamera/py_camera_manager.h index 56bea13d..3525057d 100644 --- a/src/py/libcamera/py_camera_manager.h +++ b/src/py/libcamera/py_camera_manager.h @@ -39,7 +39,7 @@ private: LIBCAMERA_TSA_GUARDED_BY(completedRequestsMutex_); void writeFd(); - void readFd(); + int readFd(); void pushRequest(Request *req); std::vector getCompletedRequests(); }; diff --git a/test/py/unittests.py b/test/py/unittests.py index 9adc4337..6dea80fc 100755 --- a/test/py/unittests.py +++ b/test/py/unittests.py @@ -207,9 +207,16 @@ class SimpleCaptureMethods(CameraTesterBase): reqs = None gc.collect() + sel = selectors.DefaultSelector() + sel.register(cm.event_fd, selectors.EVENT_READ) + reqs = [] while True: + events = sel.select() + if not events: + continue + ready_reqs = cm.get_ready_requests() reqs += ready_reqs From patchwork Fri Jul 1 08:45: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: 16502 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 86E59C3273 for ; Fri, 1 Jul 2022 08:45:53 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 16E8E656A4; Fri, 1 Jul 2022 10:45:53 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1656665153; bh=WXMh8izmwtfH9KXHzNqFbQLxbsXXQhn41eDBc26LxMU=; 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=OpB4nyua1N7+sVIE5glekDPIFMahr4u+0/fNDZRk0xaMRBYQtaoXy0aqQIWxMZrpz H2T87Pe8m0MBJl+idmdW37babb5mhJBVxyBvE/UZstSFOWRe+V4reQkCz5l3KxCPXi O/Mk6iXsAVRN17CyZZtKb0P4OJab6NHRcFxFuO8zbxPRRFpk6BzUCYv9pv4MGQylj/ Y3yTMKTGsZbOSNHLjzqFwKXam4Z1j4NPgFUWdZ/x6K4zv5vwYaOOXVR/foURBmloUH Sj41S6kolr6FA5NBLC3yUX9Xp1jPBcXfV3CxsXMjqJ+E+6x7eG2/HVnKiywi5PpRXP ldKnSEZB/s+6g== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 830D165662 for ; Fri, 1 Jul 2022 10:45:45 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="PXPvnAOc"; dkim-atps=neutral Received: from deskari.lan (91-158-154-79.elisa-laajakaista.fi [91.158.154.79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E5E926D1; Fri, 1 Jul 2022 10:45:44 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1656665145; bh=WXMh8izmwtfH9KXHzNqFbQLxbsXXQhn41eDBc26LxMU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=PXPvnAOc1fCyX/D6UiQQp3IdL4M0h2fQEUNk2iZJCGOHV6rKNZm6o/xzGgemAbSqH SgA90dj5KddNzvSRjSRW79Tj/RZO6G0cJ/u5cODJmrv7w+Zm8ooEgOjw9lfnVog1Ke EbBTd4C8w5rHZhQ2OI/PKjOGUrfbzZevLj38o0tk= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Fri, 1 Jul 2022 11:45:14 +0300 Message-Id: <20220701084521.31831-11-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> References: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 10/17] py: Use exceptions instead of returning error codes 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" We have multiple methods which return an error code, mimicing the C++ API. Using exceptions is more natural in the Python API, so change all those methods to raise an Exception instead. Signed-off-by: Tomi Valkeinen Reviewed-by: Jacopo Mondi --- src/py/cam/cam.py | 16 +---- src/py/examples/simple-cam.py | 15 +--- src/py/examples/simple-capture.py | 21 ++---- src/py/examples/simple-continuous-capture.py | 21 ++---- src/py/libcamera/py_main.cpp | 62 ++++++++++++---- test/py/unittests.py | 76 +++++++------------- 6 files changed, 93 insertions(+), 118 deletions(-) diff --git a/src/py/cam/cam.py b/src/py/cam/cam.py index 2701d937..6b6b678b 100755 --- a/src/py/cam/cam.py +++ b/src/py/cam/cam.py @@ -158,9 +158,7 @@ class CameraContext: print('Camera configuration adjusted') - r = self.camera.configure(camconfig) - if r != 0: - raise Exception('Configure failed') + self.camera.configure(camconfig) self.stream_names = {} self.streams = [] @@ -175,12 +173,7 @@ class CameraContext: allocator = libcam.FrameBufferAllocator(self.camera) for stream in self.streams: - ret = allocator.allocate(stream) - if ret < 0: - print('Cannot allocate buffers') - exit(-1) - - allocated = len(allocator.buffers(stream)) + allocated = allocator.allocate(stream) print('{}-{}: Allocated {} buffers'.format(self.id, self.stream_names[stream], allocated)) @@ -205,10 +198,7 @@ class CameraContext: buffers = self.allocator.buffers(stream) buffer = buffers[buf_num] - ret = request.add_buffer(stream, buffer) - if ret < 0: - print('Can not set buffer for request') - exit(-1) + request.add_buffer(stream, buffer) requests.append(request) diff --git a/src/py/examples/simple-cam.py b/src/py/examples/simple-cam.py index b3e97ca7..1cd1019d 100755 --- a/src/py/examples/simple-cam.py +++ b/src/py/examples/simple-cam.py @@ -259,12 +259,7 @@ def main(): allocator = libcam.FrameBufferAllocator(camera) for cfg in config: - ret = allocator.allocate(cfg.stream) - if ret < 0: - print('Can\'t allocate buffers') - return -1 - - allocated = len(allocator.buffers(cfg.stream)) + allocated = allocator.allocate(cfg.stream) print(f'Allocated {allocated} buffers for stream') # -------------------------------------------------------------------- @@ -289,15 +284,9 @@ def main(): requests = [] for i in range(len(buffers)): request = camera.create_request() - if not request: - print('Can\'t create request') - return -1 buffer = buffers[i] - ret = request.add_buffer(stream, buffer) - if ret < 0: - print('Can\'t set buffer for request') - return -1 + request.add_buffer(stream, buffer) # Controls can be added to a request on a per frame basis. request.set_control(libcam.controls.Brightness, 0.5) diff --git a/src/py/examples/simple-capture.py b/src/py/examples/simple-capture.py index 5f93574f..4b85408f 100755 --- a/src/py/examples/simple-capture.py +++ b/src/py/examples/simple-capture.py @@ -43,8 +43,7 @@ def main(): # Acquire the camera for our use - ret = cam.acquire() - assert ret == 0 + cam.acquire() # Configure the camera @@ -60,8 +59,7 @@ def main(): w, h = [int(v) for v in args.size.split('x')] stream_config.size = libcam.Size(w, h) - ret = cam.configure(cam_config) - assert ret == 0 + cam.configure(cam_config) print(f'Capturing {TOTAL_FRAMES} frames with {stream_config}') @@ -83,15 +81,13 @@ def main(): req = cam.create_request(i) buffer = allocator.buffers(stream)[i] - ret = req.add_buffer(stream, buffer) - assert ret == 0 + req.add_buffer(stream, buffer) reqs.append(req) # Start the camera - ret = cam.start() - assert ret == 0 + cam.start() # frames_queued and frames_done track the number of frames queued and done @@ -101,8 +97,7 @@ def main(): # Queue the requests to the camera for req in reqs: - ret = cam.queue_request(req) - assert ret == 0 + cam.queue_request(req) frames_queued += 1 # The main loop. Wait for the queued Requests to complete, process them, @@ -155,13 +150,11 @@ def main(): # Stop the camera - ret = cam.stop() - assert ret == 0 + cam.stop() # Release the camera - ret = cam.release() - assert ret == 0 + cam.release() return 0 diff --git a/src/py/examples/simple-continuous-capture.py b/src/py/examples/simple-continuous-capture.py index 26a8060b..e1cb931e 100755 --- a/src/py/examples/simple-continuous-capture.py +++ b/src/py/examples/simple-continuous-capture.py @@ -28,8 +28,7 @@ class CameraCaptureContext: # Acquire the camera for our use - ret = cam.acquire() - assert ret == 0 + cam.acquire() # Configure the camera @@ -37,8 +36,7 @@ class CameraCaptureContext: stream_config = cam_config.at(0) - ret = cam.configure(cam_config) - assert ret == 0 + cam.configure(cam_config) stream = stream_config.stream @@ -62,8 +60,7 @@ class CameraCaptureContext: req = cam.create_request(idx) buffer = allocator.buffers(stream)[i] - ret = req.add_buffer(stream, buffer) - assert ret == 0 + req.add_buffer(stream, buffer) self.reqs.append(req) @@ -73,13 +70,11 @@ class CameraCaptureContext: def uninit_camera(self): # Stop the camera - ret = self.cam.stop() - assert ret == 0 + self.cam.stop() # Release the camera - ret = self.cam.release() - assert ret == 0 + self.cam.release() # A container class for our state @@ -145,8 +140,7 @@ class CaptureContext: for cam_ctx in self.camera_contexts: for req in cam_ctx.reqs: - ret = cam_ctx.cam.queue_request(req) - assert ret == 0 + cam_ctx.cam.queue_request(req) # Use Selector to wait for events from the camera and from the keyboard @@ -177,8 +171,7 @@ def main(): # Start the cameras for cam_ctx in ctx.camera_contexts: - ret = cam_ctx.cam.start() - assert ret == 0 + cam_ctx.cam.start() ctx.capture() diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp index e7d078b5..6cd99919 100644 --- a/src/py/libcamera/py_main.cpp +++ b/src/py/libcamera/py_main.cpp @@ -111,8 +111,19 @@ PYBIND11_MODULE(_libcamera, m) pyCamera .def_property_readonly("id", &Camera::id) - .def("acquire", &Camera::acquire) - .def("release", &Camera::release) + .def("acquire", [](Camera &self) { + int ret = self.acquire(); + if (ret) + throw std::system_error(-ret, std::generic_category(), + "Failed to acquire camera"); + }) + .def("release", [](Camera &self) { + int ret = self.release(); + /* \todo Should we ignore the error? */ + if (ret) + throw std::system_error(-ret, std::generic_category(), + "Failed to release camera"); + }) .def("start", [](Camera &self, const std::unordered_map &controls) { /* \todo What happens if someone calls start() multiple times? */ @@ -132,20 +143,20 @@ PYBIND11_MODULE(_libcamera, m) int ret = self.start(&controlList); if (ret) { self.requestCompleted.disconnect(); - return ret; + throw std::system_error(-ret, std::generic_category(), + "Failed to start camera"); } - - return 0; }, py::arg("controls") = std::unordered_map()) .def("stop", [](Camera &self) { int ret = self.stop(); - if (ret) - return ret; self.requestCompleted.disconnect(); - return 0; + /* \todo Should we just ignore the error? */ + if (ret) + throw std::system_error(-ret, std::generic_category(), + "Failed to start camera"); }) .def("__str__", [](Camera &self) { @@ -154,9 +165,20 @@ PYBIND11_MODULE(_libcamera, m) /* Keep the camera alive, as StreamConfiguration contains a Stream* */ .def("generate_configuration", &Camera::generateConfiguration, py::keep_alive<0, 1>()) - .def("configure", &Camera::configure) + .def("configure", [](Camera &self, CameraConfiguration *config) { + int ret = self.configure(config); + if (ret) + throw std::system_error(-ret, std::generic_category(), + "Failed to configure camera"); + }) - .def("create_request", &Camera::createRequest, py::arg("cookie") = 0) + .def("create_request", [](Camera &self, uint64_t cookie) { + std::unique_ptr req = self.createRequest(cookie); + if (!req) + throw std::system_error(ENOMEM, std::generic_category(), + "Failed to create request"); + return req; + }, py::arg("cookie") = 0) .def("queue_request", [](Camera &self, Request *req) { py::object py_req = py::cast(req); @@ -169,10 +191,11 @@ PYBIND11_MODULE(_libcamera, m) py_req.inc_ref(); int ret = self.queueRequest(req); - if (ret) + if (ret) { py_req.dec_ref(); - - return ret; + throw std::system_error(-ret, std::generic_category(), + "Failed to queue request"); + } }) .def_property_readonly("streams", [](Camera &self) { @@ -250,7 +273,13 @@ PYBIND11_MODULE(_libcamera, m) pyFrameBufferAllocator .def(py::init>(), py::keep_alive<1, 2>()) - .def("allocate", &FrameBufferAllocator::allocate) + .def("allocate", [](FrameBufferAllocator &self, Stream *stream) { + int ret = self.allocate(stream); + if (ret < 0) + throw std::system_error(-ret, std::generic_category(), + "Failed to queue request"); + return ret; + }) .def_property_readonly("allocated", &FrameBufferAllocator::allocated) /* Create a list of FrameBuffers, where each FrameBuffer has a keep-alive to FrameBufferAllocator */ .def("buffers", [](FrameBufferAllocator &self, Stream *stream) { @@ -327,7 +356,10 @@ PYBIND11_MODULE(_libcamera, m) pyRequest /* \todo Fence is not supported, so we cannot expose addBuffer() directly */ .def("add_buffer", [](Request &self, const Stream *stream, FrameBuffer *buffer) { - return self.addBuffer(stream, buffer); + int ret = self.addBuffer(stream, buffer); + if (ret) + throw std::system_error(-ret, std::generic_category(), + "Failed to add buffer"); }, py::keep_alive<1, 3>()) /* Request keeps Framebuffer alive */ .def_property_readonly("status", &Request::status) .def_property_readonly("buffers", &Request::buffers) diff --git a/test/py/unittests.py b/test/py/unittests.py index 6dea80fc..794e46be 100755 --- a/test/py/unittests.py +++ b/test/py/unittests.py @@ -42,31 +42,26 @@ class SimpleTestMethods(BaseTestCase): cam = cm.get('platform/vimc.0 Sensor B') self.assertIsNotNone(cam) - ret = cam.acquire() - self.assertZero(ret) + cam.acquire() - ret = cam.release() - self.assertZero(ret) + cam.release() def test_double_acquire(self): cm = libcam.CameraManager.singleton() cam = cm.get('platform/vimc.0 Sensor B') self.assertIsNotNone(cam) - ret = cam.acquire() - self.assertZero(ret) + cam.acquire() libcam.log_set_level('Camera', 'FATAL') - ret = cam.acquire() - self.assertEqual(ret, -errno.EBUSY) + with self.assertRaises(RuntimeError): + cam.acquire() libcam.log_set_level('Camera', 'ERROR') - ret = cam.release() - self.assertZero(ret) + cam.release() - ret = cam.release() - # I expected EBUSY, but looks like double release works fine - self.assertZero(ret) + # I expected exception here, but looks like double release works fine + cam.release() class CameraTesterBase(BaseTestCase): @@ -80,11 +75,7 @@ class CameraTesterBase(BaseTestCase): self.cm = None self.skipTest('No vimc found') - ret = self.cam.acquire() - if ret != 0: - self.cam = None - self.cm = None - raise Exception('Failed to acquire camera') + self.cam.acquire() self.wr_cam = weakref.ref(self.cam) self.wr_cm = weakref.ref(self.cm) @@ -93,9 +84,7 @@ class CameraTesterBase(BaseTestCase): # If a test fails, the camera may be in running state. So always stop. self.cam.stop() - ret = self.cam.release() - if ret != 0: - raise Exception('Failed to release camera') + self.cam.release() self.cam = None self.cm = None @@ -115,8 +104,7 @@ class AllocatorTestMethods(CameraTesterBase): streamconfig = camconfig.at(0) wr_streamconfig = weakref.ref(streamconfig) - ret = cam.configure(camconfig) - self.assertZero(ret) + cam.configure(camconfig) stream = streamconfig.stream wr_stream = weakref.ref(stream) @@ -129,8 +117,8 @@ class AllocatorTestMethods(CameraTesterBase): self.assertIsNotNone(wr_streamconfig()) allocator = libcam.FrameBufferAllocator(cam) - ret = allocator.allocate(stream) - self.assertTrue(ret > 0) + num_bufs = allocator.allocate(stream) + self.assertTrue(num_bufs > 0) wr_allocator = weakref.ref(allocator) buffers = allocator.buffers(stream) @@ -173,14 +161,13 @@ class SimpleCaptureMethods(CameraTesterBase): self.assertIsNotNone(fmts) fmts = None - ret = cam.configure(camconfig) - self.assertZero(ret) + cam.configure(camconfig) stream = streamconfig.stream allocator = libcam.FrameBufferAllocator(cam) - ret = allocator.allocate(stream) - self.assertTrue(ret > 0) + num_bufs = allocator.allocate(stream) + self.assertTrue(num_bufs > 0) num_bufs = len(allocator.buffers(stream)) @@ -190,19 +177,16 @@ class SimpleCaptureMethods(CameraTesterBase): self.assertIsNotNone(req) buffer = allocator.buffers(stream)[i] - ret = req.add_buffer(stream, buffer) - self.assertZero(ret) + req.add_buffer(stream, buffer) reqs.append(req) buffer = None - ret = cam.start() - self.assertZero(ret) + cam.start() for req in reqs: - ret = cam.queue_request(req) - self.assertZero(ret) + cam.queue_request(req) reqs = None gc.collect() @@ -230,8 +214,7 @@ class SimpleCaptureMethods(CameraTesterBase): reqs = None gc.collect() - ret = cam.stop() - self.assertZero(ret) + cam.stop() def test_select(self): cm = self.cm @@ -245,14 +228,13 @@ class SimpleCaptureMethods(CameraTesterBase): self.assertIsNotNone(fmts) fmts = None - ret = cam.configure(camconfig) - self.assertZero(ret) + cam.configure(camconfig) stream = streamconfig.stream allocator = libcam.FrameBufferAllocator(cam) - ret = allocator.allocate(stream) - self.assertTrue(ret > 0) + num_bufs = allocator.allocate(stream) + self.assertTrue(num_bufs > 0) num_bufs = len(allocator.buffers(stream)) @@ -262,19 +244,16 @@ class SimpleCaptureMethods(CameraTesterBase): self.assertIsNotNone(req) buffer = allocator.buffers(stream)[i] - ret = req.add_buffer(stream, buffer) - self.assertZero(ret) + req.add_buffer(stream, buffer) reqs.append(req) buffer = None - ret = cam.start() - self.assertZero(ret) + cam.start() for req in reqs: - ret = cam.queue_request(req) - self.assertZero(ret) + cam.queue_request(req) reqs = None gc.collect() @@ -303,8 +282,7 @@ class SimpleCaptureMethods(CameraTesterBase): reqs = None gc.collect() - ret = cam.stop() - self.assertZero(ret) + cam.stop() # Recursively expand slist's objects into olist, using seen to track already From patchwork Fri Jul 1 08:45: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: 16504 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 4A889BD808 for ; Fri, 1 Jul 2022 08:45:56 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0517B656AA; Fri, 1 Jul 2022 10:45:56 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1656665156; bh=/YkbYWzQtsOn9IeurNkp3sgIkzOM+11dUkx+At5lrSU=; 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=D/Ujq4GO06hgQtQ9QGI65W4BJnFeyOMHb9hEZeKEadTiJrnYOGjXHcPx7iYoeh1EN CYY5FhhPyOkpFjZ0TywUJuTCHAQi2OhDO7KYENiIXKTlCAuANKDqK+W/APjwVGrgGd LHDshrtjgip0NGpLWw1kdz/WFzGMPFFisLoHqeIZhCTcINOrs9CttH8oWRHf8kgoV4 FS+tr0Btc6FsDrF7GbdKqEDxxkjPhjQcUlK0KE6CAfFQXLLjpVbGZU4aP4Vz9x4rOu ulwBPlJDgmzmn2BaWO4e17MTczsTsgN4N5rx1ikK138nvLdYLLJlZgoFYskc5zH1uA xCbRPwZWnyDtA== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id F407265652 for ; Fri, 1 Jul 2022 10:45:45 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="vHNdKkBp"; dkim-atps=neutral Received: from deskari.lan (91-158-154-79.elisa-laajakaista.fi [91.158.154.79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 74E0725C; Fri, 1 Jul 2022 10:45:45 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1656665145; bh=/YkbYWzQtsOn9IeurNkp3sgIkzOM+11dUkx+At5lrSU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=vHNdKkBpuugy+5Po2MIvTxankoLgX9qazH4VxlUj0nDNnlvjz57J9Syc0CjAmQ+6E YnPWHHifctGF+CC8U0Gw9pbO8kag9LKWeaSlVDrc88wncHkp8oYU8fhglf3Rg5QHTe izdr+qxxwJg9xqUFpmcRl0refcd6Ol/hgPznYytI= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Fri, 1 Jul 2022 11:45:15 +0300 Message-Id: <20220701084521.31831-12-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> References: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 11/17] py: New event handling 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 the moment the Python bindings only handle the requestCompleted events. But we have others, bufferCompleted and disconnect from the Camera, and cameraAdded and cameraRemoved from the CameraManager. This patch makes all those events available to the users. The get_ready_requests() method is now deprecated, but available to keep backward compatibility. The new event handling works like get_ready_requests(), but instead of returning only Requests from requestCompleted events, it returns all event types using a new Event class. Additionally camera.stop() has been changed to return events for that camera. This serves two purposes: first, it removes the requestCompleted events from the event queue, thus preventing the old events being returned when the camera is started again, and second, it allows the user to process those events if it so wants. All other event types are always collected and returned, except bufferCompleted which needs to be enabled by setting the CameraManager.buffer_completed_active to True. This is to reduce the overhead a bit. It is not clear if this is a necessary optimization or not. TODO: Documentation. Signed-off-by: Tomi Valkeinen --- src/py/libcamera/py_camera_manager.cpp | 191 +++++++++++++++++++++++-- src/py/libcamera/py_camera_manager.h | 64 ++++++++- src/py/libcamera/py_main.cpp | 45 +++++- 3 files changed, 276 insertions(+), 24 deletions(-) diff --git a/src/py/libcamera/py_camera_manager.cpp b/src/py/libcamera/py_camera_manager.cpp index 3dd8668e..d1d63690 100644 --- a/src/py/libcamera/py_camera_manager.cpp +++ b/src/py/libcamera/py_camera_manager.cpp @@ -5,6 +5,7 @@ #include "py_camera_manager.h" +#include #include #include #include @@ -33,11 +34,17 @@ PyCameraManager::PyCameraManager() if (ret) throw std::system_error(-ret, std::generic_category(), "Failed to start CameraManager"); + + cameraManager_->cameraAdded.connect(this, &PyCameraManager::handleCameraAdded); + cameraManager_->cameraRemoved.connect(this, &PyCameraManager::handleCameraRemoved); } PyCameraManager::~PyCameraManager() { LOG(Python, Debug) << "~PyCameraManager()"; + + cameraManager_->cameraAdded.disconnect(); + cameraManager_->cameraRemoved.disconnect(); } py::list PyCameraManager::cameras() @@ -58,6 +65,50 @@ py::list PyCameraManager::cameras() return l; } +PyCameraEvent PyCameraManager::convertEvent(const CameraEvent &event) +{ + PyCameraEvent pyevent; + + pyevent.type_ = event.type_; + + /* + * We need to set a keep-alive here so that the camera keeps the + * camera manager alive. + */ + py::object py_cm = py::cast(this); + py::object py_cam = py::cast(event.camera_); + py::detail::keep_alive_impl(py_cam, py_cm); + + pyevent.camera_ = py_cam; + + switch (event.type_) { + case CameraEventType::CameraAdded: + case CameraEventType::CameraRemoved: + case CameraEventType::Disconnect: + /* No additional parameters to add */ + break; + + case CameraEventType::BufferCompleted: { + pyevent.request_ = py::cast(event.request_); + pyevent.fb_ = py::cast(event.fb_); + break; + } + case CameraEventType::RequestCompleted: { + pyevent.request_ = py::cast(event.request_); + + /* Decrease the ref increased in Camera.queue_request() */ + pyevent.request_.dec_ref(); + + break; + } + default: + ASSERT(false); + } + + return pyevent; +} + +/* DEPRECATED */ std::vector PyCameraManager::getReadyRequests() { int ret = readFd(); @@ -70,21 +121,125 @@ std::vector PyCameraManager::getReadyRequests() std::vector py_reqs; - for (Request *request : getCompletedRequests()) { - py::object o = py::cast(request); - /* Decrease the ref increased in Camera.queue_request() */ - o.dec_ref(); - py_reqs.push_back(o); + for (const auto &ev : getEvents()) { + if (ev.type_ != CameraEventType::RequestCompleted) + continue; + + PyCameraEvent pyev = convertEvent(ev); + py_reqs.push_back(pyev.request_); } return py_reqs; } +std::vector PyCameraManager::getPyEvents() +{ + int ret = readFd(); + + if (ret == EAGAIN) { + LOG(Python, Debug) << "No events"; + return {}; + } + + if (ret != 0) + throw std::system_error(ret, std::generic_category()); + + std::vector events = getEvents(); + + LOG(Python, Debug) << "Get " << events.size() << " events"; + + std::vector pyevents(events.size()); + + std::transform(events.begin(), events.end(), pyevents.begin(), + [this](const CameraEvent &ev) { + return convertEvent(ev); + }); + + return pyevents; +} + +static bool isCameraSpecificEvent(const CameraEvent &event, std::shared_ptr &camera) +{ + return event.camera_ == camera && + (event.type_ == CameraEventType::RequestCompleted || + event.type_ == CameraEventType::BufferCompleted || + event.type_ == CameraEventType::Disconnect); +} + +std::vector PyCameraManager::getPyCameraEvents(std::shared_ptr camera) +{ + MutexLocker guard(eventsMutex_); + + std::vector pyevents; + + /* Get events related to the given camera */ + + for (const auto &event : events_) { + if (!isCameraSpecificEvent(event, camera)) + continue; + + PyCameraEvent pyev = convertEvent(event); + pyevents.push_back(pyev); + } + + /* Drop the events from the events_ list */ + + events_.erase(std::remove_if(events_.begin(), events_.end(), + [&camera](const CameraEvent &ev) { + return isCameraSpecificEvent(ev, camera); + }), + events_.end()); + + LOG(Python, Debug) << "Get " << pyevents.size() << " camera events, " + << events_.size() << " unhandled events left"; + + return pyevents; +} + /* Note: Called from another thread */ -void PyCameraManager::handleRequestCompleted(Request *req) +void PyCameraManager::handleBufferCompleted(std::shared_ptr cam, Request *req, FrameBuffer *fb) { - pushRequest(req); - writeFd(); + if (!bufferCompletedEventActive_) + return; + + CameraEvent ev(CameraEventType::BufferCompleted, cam); + ev.request_ = req; + ev.fb_ = fb; + + pushEvent(ev); +} + +/* Note: Called from another thread */ +void PyCameraManager::handleRequestCompleted(std::shared_ptr cam, Request *req) +{ + CameraEvent ev(CameraEventType::RequestCompleted, cam); + ev.request_ = req; + + pushEvent(ev); +} + +/* Note: Called from another thread */ +void PyCameraManager::handleDisconnected(std::shared_ptr cam) +{ + CameraEvent ev(CameraEventType::Disconnect, cam); + + pushEvent(ev); +} + +/* Note: Called from another thread */ +void PyCameraManager::handleCameraAdded(std::shared_ptr cam) +{ + CameraEvent ev(CameraEventType::CameraAdded, cam); + + pushEvent(ev); +} + +/* Note: Called from another thread */ +void PyCameraManager::handleCameraRemoved(std::shared_ptr cam) +{ + CameraEvent ev(CameraEventType::CameraRemoved, cam); + + pushEvent(ev); } void PyCameraManager::writeFd() @@ -110,16 +265,22 @@ int PyCameraManager::readFd() return 0; } -void PyCameraManager::pushRequest(Request *req) +void PyCameraManager::pushEvent(const CameraEvent &ev) { - MutexLocker guard(completedRequestsMutex_); - completedRequests_.push_back(req); + MutexLocker guard(eventsMutex_); + events_.push_back(ev); + + writeFd(); + + LOG(Python, Debug) << "Queued events: " << events_.size(); } -std::vector PyCameraManager::getCompletedRequests() +std::vector PyCameraManager::getEvents() { - std::vector v; - MutexLocker guard(completedRequestsMutex_); - swap(v, completedRequests_); + std::vector v; + + MutexLocker guard(eventsMutex_); + swap(v, events_); + return v; } diff --git a/src/py/libcamera/py_camera_manager.h b/src/py/libcamera/py_camera_manager.h index 3525057d..b313ba9b 100644 --- a/src/py/libcamera/py_camera_manager.h +++ b/src/py/libcamera/py_camera_manager.h @@ -13,6 +13,47 @@ using namespace libcamera; +enum class CameraEventType { + Undefined = 0, + CameraAdded, + CameraRemoved, + Disconnect, + RequestCompleted, + BufferCompleted, +}; + +/* + * This event struct is used internally to queue the events we receive from + * other threads. + */ +struct CameraEvent { + CameraEvent(CameraEventType type, std::shared_ptr camera) + : type_(type), camera_(camera) + { + } + + CameraEventType type_ = CameraEventType::Undefined; + + std::shared_ptr camera_; + + Request *request_ = nullptr; + FrameBuffer *fb_ = nullptr; +}; + +/* + * This event struct is passed to Python. We need to use pybind11::object here + * instead of a C++ pointer so that we keep a ref to the Request, and a + * keep-alive from the camera to the camera manager. + */ +struct PyCameraEvent { + CameraEventType type_ = CameraEventType::Undefined; + + pybind11::object camera_; + + pybind11::object request_; + pybind11::object fb_; +}; + class PyCameraManager { public: @@ -26,20 +67,29 @@ public: int eventFd() const { return eventFd_.get(); } - std::vector getReadyRequests(); + std::vector getReadyRequests(); /* DEPRECATED */ + std::vector getPyEvents(); + std::vector getPyCameraEvents(std::shared_ptr camera); - void handleRequestCompleted(Request *req); + void handleBufferCompleted(std::shared_ptr cam, Request *req, FrameBuffer *fb); + void handleRequestCompleted(std::shared_ptr cam, Request *req); + void handleDisconnected(std::shared_ptr cam); + void handleCameraAdded(std::shared_ptr cam); + void handleCameraRemoved(std::shared_ptr cam); + bool bufferCompletedEventActive_ = false; private: std::unique_ptr cameraManager_; UniqueFD eventFd_; - libcamera::Mutex completedRequestsMutex_; - std::vector completedRequests_ - LIBCAMERA_TSA_GUARDED_BY(completedRequestsMutex_); + libcamera::Mutex eventsMutex_; + std::vector events_ + LIBCAMERA_TSA_GUARDED_BY(eventsMutex_); void writeFd(); int readFd(); - void pushRequest(Request *req); - std::vector getCompletedRequests(); + void pushEvent(const CameraEvent &ev); + std::vector getEvents(); + + PyCameraEvent convertEvent(const CameraEvent &event); }; diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp index 6cd99919..b4f756d7 100644 --- a/src/py/libcamera/py_main.cpp +++ b/src/py/libcamera/py_main.cpp @@ -58,6 +58,7 @@ PYBIND11_MODULE(_libcamera, m) * https://pybind11.readthedocs.io/en/latest/advanced/misc.html#avoiding-c-types-in-docstrings */ + auto pyEvent = py::class_(m, "Event"); auto pyCameraManager = py::class_(m, "CameraManager"); auto pyCamera = py::class_(m, "Camera"); auto pyCameraConfiguration = py::class_(m, "CameraConfiguration"); @@ -90,6 +91,21 @@ PYBIND11_MODULE(_libcamera, m) m.def("log_set_level", &logSetLevel); /* Classes */ + + py::enum_(pyEvent, "Type") + .value("Undefined", CameraEventType::Undefined) + .value("CameraAdded", CameraEventType::CameraAdded) + .value("CameraRemoved", CameraEventType::CameraRemoved) + .value("Disconnect", CameraEventType::Disconnect) + .value("RequestCompleted", CameraEventType::RequestCompleted) + .value("BufferCompleted", CameraEventType::BufferCompleted); + + pyEvent + .def_readonly("type", &PyCameraEvent::type_) + .def_readonly("camera", &PyCameraEvent::camera_) + .def_readonly("request", &PyCameraEvent::request_) + .def_readonly("fb", &PyCameraEvent::fb_); + pyCameraManager .def_static("singleton", []() { std::shared_ptr cm = gCameraManager.lock(); @@ -107,7 +123,13 @@ PYBIND11_MODULE(_libcamera, m) .def_property_readonly("cameras", &PyCameraManager::cameras) .def_property_readonly("event_fd", &PyCameraManager::eventFd) - .def("get_ready_requests", &PyCameraManager::getReadyRequests); + + /* DEPRECATED */ + .def("get_ready_requests", &PyCameraManager::getReadyRequests) + + .def("get_events", &PyCameraManager::getPyEvents) + + .def_readwrite("buffer_completed_active", &PyCameraManager::bufferCompletedEventActive_); pyCamera .def_property_readonly("id", &Camera::id) @@ -131,7 +153,17 @@ PYBIND11_MODULE(_libcamera, m) auto cm = gCameraManager.lock(); ASSERT(cm); - self.requestCompleted.connect(cm.get(), &PyCameraManager::handleRequestCompleted); + self.requestCompleted.connect(&self, [cm, camera=self.shared_from_this()](Request *req) { + cm->handleRequestCompleted(camera, req); + }); + + self.bufferCompleted.connect(&self, [cm, camera=self.shared_from_this()](Request *req, FrameBuffer *fb) { + cm->handleBufferCompleted(camera, req, fb); + }); + + self.disconnected.connect(&self, [cm, camera=self.shared_from_this()]() { + cm->handleDisconnected(camera); + }); ControlList controlList(self.controls()); @@ -152,11 +184,20 @@ PYBIND11_MODULE(_libcamera, m) int ret = self.stop(); self.requestCompleted.disconnect(); + self.bufferCompleted.disconnect(); + self.disconnected.disconnect(); + + auto cm = gCameraManager.lock(); + ASSERT(cm); + + auto l = cm->getPyCameraEvents(self.shared_from_this()); /* \todo Should we just ignore the error? */ if (ret) throw std::system_error(-ret, std::generic_category(), "Failed to start camera"); + + return l; }) .def("__str__", [](Camera &self) { From patchwork Fri Jul 1 08:45: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: 16503 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 BECF8BD808 for ; Fri, 1 Jul 2022 08:45:55 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 86C7365650; Fri, 1 Jul 2022 10:45:55 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1656665155; bh=v0U9bNrGi3HWYfGUSCLofRQkPLlgOPEtaHgIn/WwQb8=; 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=id/mCrqJ1NxImEI39n68OSAjMiV35D4jSExQ7v25ZdTVUwAt2MbfrNvt+pWwNw0l6 3S2z2Rj5XFpC2OrGDIWHmjPuovO+uq8KgXKoZllQVCH5ql+Iil5w4tiTVia5rlfIbU scXkRz5xjZKmoPdJEbkIimgpT2hN0BU5aMRWA0V4g/yMVl4c/+9HPOrN2vbRZPdP3Z MK1pLHFHlLqUB+VFqxzAnchadr8nQib4f0YZuVw8tkGkPjVP5qgF6o6ck2iqlQ7Apd a/ItgIvkAEt/AXWgrQXu/Wfz7QqdqOb3qU1vv4sM53JnHOs6uDrrBn1mZy4ztSn1LO G38Kh3OwFG/EA== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6DBA96565C for ; Fri, 1 Jul 2022 10:45:46 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="hvgjkFTx"; dkim-atps=neutral Received: from deskari.lan (91-158-154-79.elisa-laajakaista.fi [91.158.154.79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E6A6F6BB; Fri, 1 Jul 2022 10:45:45 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1656665146; bh=v0U9bNrGi3HWYfGUSCLofRQkPLlgOPEtaHgIn/WwQb8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=hvgjkFTxoY7D7NaVhUScMX03FM143nxoeWjfTHPPSoQtJkbMMGnA6jjs9Pr7bTXbK xp96p6z3r1mnFTrvgG+pmCkUYOegPr71+C7+GAhGhw3k+WMxdjyL7ZzWfvyqDd5pIG TiFfoYzj+qSw0GRBz+IYi0rRaWKLbL1Ct1zv/JOc= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Fri, 1 Jul 2022 11:45:16 +0300 Message-Id: <20220701084521.31831-13-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> References: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 12/17] py: cam.py: Use new events 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: Tomi Valkeinen via libcamera-devel From: Tomi Valkeinen Reply-To: Tomi Valkeinen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Convert cam.py to use the new event dispatching. In addition to handling the request-completed event, handle also disconnect, camera-added and camera-removed events (which only do a simple print). Signed-off-by: Tomi Valkeinen Reviewed-by: Jacopo Mondi --- src/py/cam/cam.py | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/py/cam/cam.py b/src/py/cam/cam.py index 6b6b678b..f19bad57 100755 --- a/src/py/cam/cam.py +++ b/src/py/cam/cam.py @@ -230,11 +230,20 @@ class CaptureState: # Called from renderer when there is a libcamera event def event_handler(self): try: - reqs = self.cm.get_ready_requests() - - for req in reqs: - ctx = next(ctx for ctx in self.contexts if ctx.idx == req.cookie) - self.__request_handler(ctx, req) + evs = self.cm.get_events() + for ev in evs: + type = ev.type + + if type == libcam.Event.Type.Undefined: + raise RuntimeError("Bad event type") + elif type == libcam.Event.Type.CameraAdded: + print('Camera added:', ev.camera) + elif type == libcam.Event.Type.CameraRemoved: + print('Camera added:', ev.camera) + elif type == libcam.Event.Type.Disconnect: + self.__disconnect_handler(ev.camera) + elif type == libcam.Event.Type.RequestCompleted: + self.__request_handler(ev.camera, ev.request) running = any(ctx.reqs_completed < ctx.opt_capture for ctx in self.contexts) return running @@ -242,7 +251,9 @@ class CaptureState: traceback.print_exc() return False - def __request_handler(self, ctx, req): + def __request_handler(self, cam, req): + ctx = next(ctx for ctx in self.contexts if ctx.camera == cam) + if req.status != libcam.Request.Status.Complete: raise Exception('{}: Request failed: {}'.format(ctx.id, req.status)) @@ -297,6 +308,9 @@ class CaptureState: ctx.camera.queue_request(req) ctx.reqs_queued += 1 + def __disconnect_handler(self, cam): + print(f'Camera {cam} disconnected') + def __capture_init(self): for ctx in self.contexts: ctx.acquire() @@ -447,6 +461,11 @@ def main(): state.do_cmd_capture() + # This is not strictly needed, but it helps to do a proper cleanup as we + # drop any unhandled events, and so makes it easier to use memory leak + # detectors. + cm.get_events() + return 0 From patchwork Fri Jul 1 08:45: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: 16505 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 E1A33BD808 for ; Fri, 1 Jul 2022 08:45:56 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8D3FA65654; Fri, 1 Jul 2022 10:45:56 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1656665156; bh=M6y+5uZi7jFH5zs87INDd42XiuZf/QXSalaa9/bjY4c=; 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=ZRNwt/nrjFkTOYlK0QHLgf4yiRg7aw+S6X7ZczipHWctLZOyHk2o1U3mdtwhy5YcQ XR1GsOc8nxRGP62Exw1lLDnpR1BzxUJLagODeaa46LjPZqmP3gpSWwFBJhIhfyD5R4 eDBIyC4CeXH3tVA22OzIlCE96Oam5FherdKQNf1sZHM8kyMXy9kmNVHTVTteDPkeX5 0vPsMGKh6E+79xj9/fkqsQv6/U/gfd53qWsh4iSZHrHq8SI3RldLfAHerWNknQUZFi ZJJpdQVI6uE3bRKW4tu6TBL7zzVKyriWp6SOQY4I2WUuG2tiC1ePeQU/vngXN8uWTt Jg5Id1fO1K3tg== 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 D512C65697 for ; Fri, 1 Jul 2022 10:45:46 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="dbhKjCtc"; dkim-atps=neutral Received: from deskari.lan (91-158-154-79.elisa-laajakaista.fi [91.158.154.79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 5AB6425C; Fri, 1 Jul 2022 10:45:46 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1656665146; bh=M6y+5uZi7jFH5zs87INDd42XiuZf/QXSalaa9/bjY4c=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dbhKjCtc55+BbVQEuTt323BOTxo+1UhNWMqzYChnNJ8aYApmuavflkYgmzX1TpyFk Zoi1YV/4VfNebhO+G2a9cSjTOLx9Hl/IjP9lYRbDU1wYzh5u9D0WOR4Fj3DwulOBLv v983tYYov8imXbw123T162IZyZw2+5PL56PzhzZU= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Fri, 1 Jul 2022 11:45:17 +0300 Message-Id: <20220701084521.31831-14-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> References: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 13/17] py: unittests.py: Use new events 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: Tomi Valkeinen via libcamera-devel From: Tomi Valkeinen Reply-To: Tomi Valkeinen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- test/py/unittests.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/py/unittests.py b/test/py/unittests.py index 794e46be..fab791d1 100755 --- a/test/py/unittests.py +++ b/test/py/unittests.py @@ -201,9 +201,9 @@ class SimpleCaptureMethods(CameraTesterBase): if not events: continue - ready_reqs = cm.get_ready_requests() - - reqs += ready_reqs + for ev in cm.get_events(): + self.assertEqual(ev.type, libcam.Event.Type.RequestCompleted) + reqs.append(ev.request) if len(reqs) == num_bufs: break @@ -267,9 +267,9 @@ class SimpleCaptureMethods(CameraTesterBase): while running: events = sel.select() for key, _ in events: - ready_reqs = cm.get_ready_requests() - - reqs += ready_reqs + for ev in cm.get_events(): + self.assertEqual(ev.type, libcam.Event.Type.RequestCompleted) + reqs.append(ev.request) if len(reqs) == num_bufs: running = False From patchwork Fri Jul 1 08:45: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: 16506 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 8FE3BBD808 for ; Fri, 1 Jul 2022 08:45:57 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 598C165657; Fri, 1 Jul 2022 10:45:57 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1656665157; bh=dEMxUwcl6KLgUabu02fgNyd1D1uOBovj3Is2gM6gduc=; 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=XEJs2dWp5Vx+A6n1oz1DqB/iSmqGJntvn/XkvIQ3OwEwdPp0zps2dRu2cSQXTHkp/ I90CF3AFWh9ZnIrDhZRjMHjrrpTv4KZAsP1cqYgvsZPMKhToXO0KMneAtskNnj4sfU SoTjl/YxPCG0exDZppLR6hR74V0fcxLkRF6j7DitOaKuAd7askuFguf89pBFjlEkX4 EyeApnWCB1GDjtJ/1u2kcdFDMr1aHIp3NttJR8TlJCZRI64WIoSm8c/xC4fKgQ6h95 EwyGZXMtfCkYDVP49gMBiDjWyEWJznK3cpbR5A3tPqTRGLLE/qhNd6L881wY5SOUY4 3TjST3YCmFJqw== 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 4F03465657 for ; Fri, 1 Jul 2022 10:45:47 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="FLEbA0P1"; dkim-atps=neutral Received: from deskari.lan (91-158-154-79.elisa-laajakaista.fi [91.158.154.79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id C6FFD6BB; Fri, 1 Jul 2022 10:45:46 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1656665147; bh=dEMxUwcl6KLgUabu02fgNyd1D1uOBovj3Is2gM6gduc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=FLEbA0P1P0aU1Y6JtXWycPVJ/INmeB+n3yUkyF6245MSD0Tdcef40S5ErNJvflhwn +quOgbSoE6jEyQONqJQ6ILGu6K8UNDksHaJWVj34mEe/qlhvFauVVfr9GfGJCLwRki EvyNA5K/5MOtelkvfKJKj1M/pn/TA1vASqTcEhxM= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Fri, 1 Jul 2022 11:45:18 +0300 Message-Id: <20220701084521.31831-15-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> References: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 14/17] py: simple-capture.py: Use new events 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: Tomi Valkeinen via libcamera-devel From: Tomi Valkeinen Reply-To: Tomi Valkeinen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Signed-off-by: Tomi Valkeinen Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/py/examples/simple-capture.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/py/examples/simple-capture.py b/src/py/examples/simple-capture.py index 4b85408f..c26e638b 100755 --- a/src/py/examples/simple-capture.py +++ b/src/py/examples/simple-capture.py @@ -107,7 +107,7 @@ def main(): sel.register(cm.event_fd, selectors.EVENT_READ) while frames_done < TOTAL_FRAMES: - # cm.get_ready_requests() does not block, so we use a Selector to wait + # cm.get_events() does not block, so we use a Selector to wait # for a camera event. Here we should almost always get a single # Request, but in some cases there could be multiple or none. @@ -115,9 +115,13 @@ def main(): if not events: continue - reqs = cm.get_ready_requests() + for ev in cm.get_events(): + # We are only interested in RequestCompleted events + if ev.type != libcam.Event.Type.RequestCompleted: + continue + + req = ev.request - for req in reqs: frames_done += 1 buffers = req.buffers From patchwork Fri Jul 1 08:45: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: 16507 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 22E26BD808 for ; Fri, 1 Jul 2022 08:45:58 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id C85AA656A3; Fri, 1 Jul 2022 10:45:57 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1656665157; bh=n1EnkpCAgGEuZsOraHgImGNrEvdPLQ6ff6kaFNZgqxg=; 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=0X3hQixHN/ydE43+/aopk4Cyz+gVvMYcuVx66Qv9NCToE28KPAd8J7JRKUPf9AuS3 uujJ6bDX+N+1DZfzbzvOaRW7tUuwliuNTZNoCbcKSVP4LMNlqX9ak+fRabPtOaMsHr Trv7lcI2mPHH+7eQLhygHXBSFt6wvPLVnrOC/mf0pWS07edLyYZ/8rpy/fp8fPLt9G t5SrUoI5qzD+QAmOML3dC4GyutYP3GOhhBoTh8V0QC4120UyhsowOndViO8CqGihi3 4zGc84EDW+lxA2rfW685b6NkgPBCbmOeWFSxpAiZM0tXhNCzp2nyIXX/7heL0RFLri 8Ng74G3Racv1w== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BE6FC65699 for ; Fri, 1 Jul 2022 10:45:47 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="s4paU6Ge"; dkim-atps=neutral Received: from deskari.lan (91-158-154-79.elisa-laajakaista.fi [91.158.154.79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 3F3D725C; Fri, 1 Jul 2022 10:45:47 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1656665147; bh=n1EnkpCAgGEuZsOraHgImGNrEvdPLQ6ff6kaFNZgqxg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=s4paU6GeshDR9ZMZ99XcIsDHBf04vO0bJPVP49N0rvrKgXl7d3uR/R8O9kbdGSgGn XNvR1m+9heTxNimTsWFL+hyM4wwCWxr2o/PtSrHeKI1nrJf79s7E7aLHModAigXwF1 JZAu2lIUktTtIOGT/BO2Sj/n8cC++3xey/QVAwr0= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Fri, 1 Jul 2022 11:45:19 +0300 Message-Id: <20220701084521.31831-16-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> References: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 15/17] py: simple-continuous-capture.py: Use new events 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: Tomi Valkeinen via libcamera-devel From: Tomi Valkeinen Reply-To: Tomi Valkeinen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Signed-off-by: Tomi Valkeinen Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/py/examples/simple-continuous-capture.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/py/examples/simple-continuous-capture.py b/src/py/examples/simple-continuous-capture.py index e1cb931e..7bc9df10 100755 --- a/src/py/examples/simple-continuous-capture.py +++ b/src/py/examples/simple-continuous-capture.py @@ -83,16 +83,17 @@ class CaptureContext: camera_contexts: list[CameraCaptureContext] = [] def handle_camera_event(self): - # cm.get_ready_requests() returns the ready requests, which in our case - # should almost always return a single Request, but in some cases there - # could be multiple or none. + # cm.get_events() returns the ready events, which in our case should + # almost always return a single RequestCompleted event, but in some + # cases there could be multiple or none. - reqs = self.cm.get_ready_requests() + for ev in self.cm.get_events(): + # We are only interested in RequestCompleted events + if ev.type != libcam.Event.Type.RequestCompleted: + continue - # Process the captured frames - - for req in reqs: - self.handle_request(req) + # Process the captured frames + self.handle_request(ev.request) return True From patchwork Fri Jul 1 08:45: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: 16508 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 91C4FBD808 for ; Fri, 1 Jul 2022 08:45:58 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 4D1E16565C; Fri, 1 Jul 2022 10:45:58 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1656665158; bh=MYlDkRTAp41zXQKsbu1oUXZKNRGPOXw62F5eXwtarUg=; 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=tyxc+zIFHFBCdOBCtOOFfNA868w2yNInbLsPLqqK3McnDSiDtu7RrOPmP/DM7di3H evF/waMrGpSxgzGug2ekLfQ2XlGP7eGGya6WfF6ZnbWTpnJarPQfipmS8/VlISBODq TN1Sq/cRRO1XPsO8RzYC9Xr7nwBdYJKYOAKYVzfMNH3bEYYsEhtoeaI4u0/cNJPJaR 7+U/TcIRc5zND3Cxy+yo7Bo2+6juD5E5cqXdSYnn87/W3B/dFSR25W1r53u2bNINSH Y7e1g45QV5stYk70h6Ulr3o/041r4Bgn8LOkA+QpPyyuQotso0ZGdG4oTaoi8RHMvP DNy1noIRrOjQA== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 34BAF65659 for ; Fri, 1 Jul 2022 10:45:48 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="S24WYZY/"; dkim-atps=neutral Received: from deskari.lan (91-158-154-79.elisa-laajakaista.fi [91.158.154.79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id AB25574A; Fri, 1 Jul 2022 10:45:47 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1656665148; bh=MYlDkRTAp41zXQKsbu1oUXZKNRGPOXw62F5eXwtarUg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=S24WYZY/bqbsZkg3GMANaNmEVikl2zVx9RxlLLGUFeFblDg3X1zlxzt/dgNBXrjT3 OLkw+8+8J+aI7nTyBiLwaONJqmOL6VZoozTAPMCDa11ObGUdGdUD9cPFC3WAJQPNsX 10QOKzx9WBh0+r4wn7kFH9xyuaymVZicbtO3KjHk= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Fri, 1 Jul 2022 11:45:20 +0300 Message-Id: <20220701084521.31831-17-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> References: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 16/17] py: simple-cam.py: Use new events 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: Tomi Valkeinen via libcamera-devel From: Tomi Valkeinen Reply-To: Tomi Valkeinen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Signed-off-by: Tomi Valkeinen Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/py/examples/simple-cam.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/py/examples/simple-cam.py b/src/py/examples/simple-cam.py index 1cd1019d..2dcf962a 100755 --- a/src/py/examples/simple-cam.py +++ b/src/py/examples/simple-cam.py @@ -19,16 +19,17 @@ TIMEOUT_SEC = 3 def handle_camera_event(cm): - # cm.get_ready_requests() returns the ready requests, which in our case - # should almost always return a single Request, but in some cases there - # could be multiple or none. + # cm.get_events() returns the ready events, which in our case should + # almost always return a single RequestCompleted event, but in some + # cases there could be multiple or none. - reqs = cm.get_ready_requests() + for ev in cm.get_events(): + # We are only interested in RequestCompleted events + if ev.type != libcam.Event.Type.RequestCompleted: + continue - # Process the captured frames - - for req in reqs: - process_request(req) + # Process the captured frames + process_request(ev.request) def process_request(request): From patchwork Fri Jul 1 08:45: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: 16509 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 0B121BD808 for ; Fri, 1 Jul 2022 08:45:59 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id B17AD656AC; Fri, 1 Jul 2022 10:45:58 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1656665158; bh=COD1ICfp6x0GrWGYRioB2UOSOOeDG2n1CiaJWo9k4JI=; 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=V1ZOyf7HyZRUFC7znqPbZdtm7Fy/eLz5Rfn8Au5WIs6Xm9qrfE74FtDiGiYFU/NHB Xfg71To2DcZAahLUgl+IOHq9G48vZD3bw1QHCkc2MZIwRG7CJt1BzpJFAimy60XKoW JJgoY8+/6co3NJq4/00bh7zXQjSHa6ky/pGST0uTA9//GA6nqETGdGBEngPydJakfl RCGcRZA6cRsIrgjEYNiHQccb3jHkVgCpfVasdqoe5aOArQ9AniJBYViMK6VvinOoxa KAV0QoY8eU8l5oI6Hv+XvNHKRA98NBnazIlZ/Diqg7RfHOfkmZIZUbOeA3xOtD4l93 /F4vXiVzPdt3A== 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 B17C365654 for ; Fri, 1 Jul 2022 10:45:48 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="BK/cBtr2"; dkim-atps=neutral Received: from deskari.lan (91-158-154-79.elisa-laajakaista.fi [91.158.154.79]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 25DA26D1; Fri, 1 Jul 2022 10:45:48 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1656665148; bh=COD1ICfp6x0GrWGYRioB2UOSOOeDG2n1CiaJWo9k4JI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=BK/cBtr2y4RUHaaOQ0tjINwT7ty1NajK20a/UVJlOWSBy0b1XYvjGlO3igCj4ROZa S/zKC6+XrQ86kycS06No5JFgc7vBkLqjBsHvd5C0rK0fYMeKtsyxZfzL05VYY/4atk 32ijAwSE5fiwJyWQ6k9uzN1kfqTQIUBmw1RyTDN0= To: libcamera-devel@lists.libcamera.org, David Plowman , Kieran Bingham , Laurent Pinchart , Jacopo Mondi Date: Fri, 1 Jul 2022 11:45:21 +0300 Message-Id: <20220701084521.31831-18-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> References: <20220701084521.31831-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 17/17] py: Add hotplug-monitor.py 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 simple example script which waits for camera hotplug events. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- src/py/examples/hotplug-monitor.py | 39 ++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/py/examples/hotplug-monitor.py diff --git a/src/py/examples/hotplug-monitor.py b/src/py/examples/hotplug-monitor.py new file mode 100644 index 00000000..5f42970c --- /dev/null +++ b/src/py/examples/hotplug-monitor.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 + +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2022, Tomi Valkeinen + +import libcamera as libcam +import selectors +import sys + + +def main(): + cm = libcam.CameraManager.singleton() + + sel = selectors.DefaultSelector() + sel.register(cm.event_fd, selectors.EVENT_READ) + + print('Waiting for camera hotplug events... (CTRL-C to exit)') + + while True: + try: + events = sel.select() + if not events: + continue + except KeyboardInterrupt: + break + + events = cm.get_events() + + for ev in events: + if ev.type == libcam.Event.Type.CameraAdded: + print('Camera added:', ev.camera) + elif ev.type == libcam.Event.Type.CameraRemoved: + print('Camera removed:', ev.camera) + + return 0 + + +if __name__ == '__main__': + sys.exit(main())