From patchwork Sat Jun 3 07:56:03 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 18686 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 40809C3200 for ; Sat, 3 Jun 2023 07:57:15 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8A02D627D3; Sat, 3 Jun 2023 09:57:11 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1685779031; bh=uwRntJ6tcHUOj/PDwdbvrW3l0VyD1l1CB6lkGhwouEE=; 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=qwKBIko/+h7ue9Y5NZ2dEuYbMz1haTdAKYrk/SIm3hn8Th35Nq6DJXITfy8igy5K/ nEJ/47woVTMd+GR9MAgqe1GU4zg8WJ40sToKiQUfalNfNei7LgjtyMHt8/YpOqyxfm Dxd1PzNDdWC9HF4H+Lx/+qbt/kIP/7gs7ZoJMOTUZjoRNqipTDCv5ejabs1CO0jXDl WPnUh03crQwfCfZHqiRXPOPz53UK1bfNrQ4CD85RU9+OOvbnjlrxVuPm9fq+IVwIyH TzULOFDp7eeU1Z5k9kG5DHnl1i7lsKtPSzcghADlJqJUI48vf2RBBBC9hqGNXrw1OJ nIODnXQa6Blnw== 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 7CFD36038F for ; Sat, 3 Jun 2023 09:57:09 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="jdvpehBd"; dkim-atps=neutral Received: from desky.lan (91-154-35-171.elisa-laajakaista.fi [91.154.35.171]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id B32A8B2A; Sat, 3 Jun 2023 09:56:45 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1685779006; bh=uwRntJ6tcHUOj/PDwdbvrW3l0VyD1l1CB6lkGhwouEE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jdvpehBdloEE5oKkvi3aY/XOz5MLljguMgbvIFaubOjIGxdf0zDLxISZclcaTH7ss HzeeRrftGInKITE1RRJEb4DZ24j1QOUR4u3cT8CCWS04h4nVAsPVO2IQ6Hz7dtAFEs 0fF5M7kWNqDSfPTl7Pze8Ua9T0gWcvzFpeWsfElQ= To: libcamera-devel@lists.libcamera.org Date: Sat, 3 Jun 2023 10:56:03 +0300 Message-Id: <20230603075615.20663-2-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> References: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 01/13] subprojects: Drop pybind11 from gitignore 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" As we no longer have pybind11 as a subproject, drop it from the gitignore. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- subprojects/.gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/subprojects/.gitignore b/subprojects/.gitignore index ebe59479..04b6271f 100644 --- a/subprojects/.gitignore +++ b/subprojects/.gitignore @@ -4,4 +4,3 @@ /libyaml /libyuv /packagecache -/pybind11-* From patchwork Sat Jun 3 07:56:04 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 18687 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 C21F5C3200 for ; Sat, 3 Jun 2023 07:57:16 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 84A98626FA; Sat, 3 Jun 2023 09:57:12 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1685779032; bh=qu4gOJwNs/TBchNgaOZzdzTmlUg6NWjrqE2Cds/Xe/A=; 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=Sr4QLSytVW4vkFIdeFPQQG0/U0XTn1nEl/iAf84Aoculf6N43lpx+yhNrRc7fBp2I KYlp13nJc0e+88m5kFVqV/2E47B7DbOHlBeDrtd/8PM3mQGiUXywVZ0icnTcvzzSC/ I4ZBmyHv/+7lcL7SmSJ7BZCQlW9BD4qcSSKxvWmFoxNoWCykEZ+tCz4gxO1BcBggiV OYxc359wwbcdv0iZep6lrOLooCINc8vRa4sRfg0gl/Bko+8/8sAj/BGe4kcmWcRGRi gGby7mu1PmAqP4oNtKLh98j+Z6dZv8Zn7OKasB//ww31BvkjLEhVIXPcmTeygRnYlv CWmRol9pKUrXg== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id DE8E16038F for ; Sat, 3 Jun 2023 09:57:09 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="BZGTskPm"; dkim-atps=neutral Received: from desky.lan (91-154-35-171.elisa-laajakaista.fi [91.154.35.171]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 58E2B468; Sat, 3 Jun 2023 09:56:46 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1685779006; bh=qu4gOJwNs/TBchNgaOZzdzTmlUg6NWjrqE2Cds/Xe/A=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=BZGTskPm9KXI81AVA6AAuEmkZa/Ff8MZ4fOzPb2IWEpaD+oHUOc56J9wm7LxzO1Ee qyln9otaA3OSdDabfzz5qLCK+X4QF5EBPd/oi1pRIzjNjptADU0kWEhljvR5Oev4iu zHac6/SSHf+lsLVWMkOiVyDtNeT+DKWPe4Zjg4kk= To: libcamera-devel@lists.libcamera.org Date: Sat, 3 Jun 2023 10:56:04 +0300 Message-Id: <20230603075615.20663-3-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> References: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 02/13] py: Fix code formatting X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Tomi Valkeinen via libcamera-devel From: Tomi Valkeinen Reply-To: Tomi Valkeinen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Fix code formatting. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- src/py/libcamera/py_main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp index fd140086..5a5f1a37 100644 --- a/src/py/libcamera/py_main.cpp +++ b/src/py/libcamera/py_main.cpp @@ -180,7 +180,7 @@ PYBIND11_MODULE(_libcamera, m) ControlList controlList(self.controls()); - for (const auto& [id, obj]: controls) { + for (const auto &[id, obj] : controls) { auto val = pyToControlValue(obj, id->type()); controlList.set(id->id(), val); } From patchwork Sat Jun 3 07:56:05 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 18688 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 73741C328F for ; Sat, 3 Jun 2023 07:57:17 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 29AE562881; Sat, 3 Jun 2023 09:57:13 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1685779033; bh=Zqj/mpGYwoku8B9aPVRIEzQwfIZZ8PoQiko92pYY0sY=; 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=1W8l86rPZaehrTdzbHbc4avfxgGOWIYiKvmO1xVomooJiuO1uZzoiqsNLD6H7uSzg rAH+YtqjMv+5F3arz5lQdPZHQvQ9zwHXT6cbXQE+Bp5ooDy3X1MIZG3aFKlcOoyyYt M1NIlkRilNzDTTN0cDhJRDohAQnX0g3zxDoye6LLJ/sVZwJ6/vozrHr8Zv9UeMooJK iCE1aH8kJ2rCxLvLk56gkT+ILppCFZwLU+q8zreB6X2kYvCuWBs38vFraGmpClcVvP KXo81I9Wufuf5RD7WRX5nfdRjivX7iYYDJlDZNxtP7wBgLc0ZAgXIAIBqK3Wg9IcjL Vw+6aqVlBp8OQ== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 7DE616038F for ; Sat, 3 Jun 2023 09:57:10 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="toHcUtLv"; dkim-atps=neutral Received: from desky.lan (91-154-35-171.elisa-laajakaista.fi [91.154.35.171]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 03318B2A; Sat, 3 Jun 2023 09:56:46 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1685779007; bh=Zqj/mpGYwoku8B9aPVRIEzQwfIZZ8PoQiko92pYY0sY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=toHcUtLvHKAQ+VRwFUt+Ebje2cibU/v9V8UOYTUpgMvjn1wqUcibqc24RmPEq/b60 FxdrKa8xWgc4CqmWA5dxoV7ZtgT57TYjMpS8CCroguT83u7hfE4jig2nPeCp8A31fb p+h+xr0CajLhckC87r4laN371BBwce3O5ptnqY3U= To: libcamera-devel@lists.libcamera.org Date: Sat, 3 Jun 2023 10:56:05 +0300 Message-Id: <20230603075615.20663-4-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> References: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 03/13] 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 specific camera. This serves two purposes: first, it removes the RequestCompleted and BufferCompleted 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. The CameraManager events (CameraAdded and CameraRemoved) are always enabled, but of the Camera events only RequestCompleted is enabled by default. Other Camera events can be enabled Camera.enable_camera_event(). Signed-off-by: Tomi Valkeinen --- Documentation/python-bindings.rst | 24 ++- src/py/libcamera/py_camera_manager.cpp | 275 +++++++++++++++++++++++-- src/py/libcamera/py_camera_manager.h | 73 ++++++- src/py/libcamera/py_main.cpp | 54 ++++- 4 files changed, 386 insertions(+), 40 deletions(-) diff --git a/Documentation/python-bindings.rst b/Documentation/python-bindings.rst index bac5cd34..8f2d76c3 100644 --- a/Documentation/python-bindings.rst +++ b/Documentation/python-bindings.rst @@ -43,17 +43,23 @@ CameraManager The Python API provides a singleton CameraManager via ``CameraManager.singleton()``. There is no need to start or stop the CameraManager. -Handling Completed Requests ---------------------------- +Event Handling +-------------- -The Python bindings do not expose the ``Camera::requestCompleted`` signal -directly as the signal is invoked from another thread and it has real-time -constraints. Instead the bindings queue the completed requests internally and -use an eventfd to inform the user that there are completed requests. +The Python bindings do not expose the signals from the C++ side directly as the +signals are invoked from another thread and they may have real-time +constraints. Instead the bindings queue the received events internally and use +an eventfd to inform the user that there are events to be handled. -The user can wait on the eventfd, and upon getting an event, use -``CameraManager.get_ready_requests()`` to clear the eventfd event and to get -the completed requests. +The user can wait on the eventfd (e.g. by using Python Selector), and use +``CameraManager.get_events()`` to reset the eventfd and get the events. + +The CameraManager events (CameraAdded and CameraRemoved) are always enabled, but +of the Camera events only RequestCompleted is enabled by default. To enable +Disconnect or BufferCompleted event, use ``Camera.enable_camera_event()``. + +The ``Camera.stop()`` method will return all events related to that Camera from +the event queue. Controls & Properties --------------------- diff --git a/src/py/libcamera/py_camera_manager.cpp b/src/py/libcamera/py_camera_manager.cpp index 9ccb7aad..83c2b063 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 @@ -35,11 +36,24 @@ 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(); +} + +void PyCameraManager::init() +{ + /* Always enable RequestCompleted for all cameras by default */ + for (auto cam : cameraManager_->cameras()) + setCameraEventFlag(cam, CameraEventType::RequestCompleted, true); } py::list PyCameraManager::cameras() @@ -60,6 +74,43 @@ py::list PyCameraManager::cameras() return l; } +PyCameraEvent PyCameraManager::convertEvent(const CameraEvent &event) +{ + /* + * 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); + + PyCameraEvent pyevent(event.type_, 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; + } + + return pyevent; +} + +/* DEPRECATED */ std::vector PyCameraManager::getReadyRequests() { int ret = readFd(); @@ -72,21 +123,207 @@ 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) << "Got " << events.size() << " events"; + + std::vector pyevents; + pyevents.reserve(events.size()); + + std::transform(events.begin(), events.end(), std::back_inserter(pyevents), + [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) +{ + std::vector events; + size_t unhandled_size; + + { + MutexLocker guard(eventsMutex_); + + /* + * Collect events related to the given camera and remove them + * from the events_ vector. + */ + + auto it = events_.begin(); + while (it != events_.end()) { + if (isCameraSpecificEvent(*it, camera)) { + events.push_back(*it); + it = events_.erase(it); + } else { + it++; + } + } + + unhandled_size = events_.size(); + } + + /* Convert events to Python events */ + + std::vector pyevents; + + for (const auto &event : events) { + PyCameraEvent pyev = convertEvent(event); + pyevents.push_back(pyev); + } + + LOG(Python, Debug) << "Got " << pyevents.size() << " camera events, " + << unhandled_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(); + CameraEvent ev(CameraEventType::BufferCompleted, cam, req, fb); + + pushEvent(ev); +} + +/* Note: Called from another thread */ +void PyCameraManager::handleRequestCompleted(std::shared_ptr cam, Request *req) +{ + CameraEvent ev(CameraEventType::RequestCompleted, cam, 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); +} + +bool PyCameraManager::getCameraEventFlag(std::shared_ptr camera, CameraEventType event_type) +{ + const uint32_t evbit = 1 << (uint32_t)event_type; + uint32_t mask = 0; + + if (auto it = camera_event_masks_.find(camera); it != camera_event_masks_.end()) + mask = it->second; + + return !!(mask & evbit); +} + +void PyCameraManager::setCameraEventFlag(std::shared_ptr camera, CameraEventType event_type, bool value) +{ + switch (event_type) { + case CameraEventType::RequestCompleted: + case CameraEventType::BufferCompleted: + case CameraEventType::Disconnect: + break; + + default: + throw std::runtime_error("Bad camera event type"); + } + + const uint32_t evbit = 1 << (uint32_t)event_type; + uint32_t mask = 0; + + if (auto it = camera_event_masks_.find(camera); it != camera_event_masks_.end()) + mask = it->second; + + bool old_val = !!(mask & evbit); + + if (old_val == value) + return; + + if (value) + mask |= evbit; + else + mask &= ~evbit; + + camera_event_masks_[camera] = mask; + + switch (event_type) { + case CameraEventType::RequestCompleted: + if (value) { + camera->requestCompleted.connect(camera.get(), [cm = this->shared_from_this(), camera](Request *req) { + cm->handleRequestCompleted(camera, req); + }); + } else { + camera->requestCompleted.disconnect(); + } + break; + + case CameraEventType::BufferCompleted: + if (value) { + camera->bufferCompleted.connect(camera.get(), [cm = this->shared_from_this(), camera](Request *req, FrameBuffer *fb) { + cm->handleBufferCompleted(camera, req, fb); + }); + } else { + camera->bufferCompleted.disconnect(); + } + break; + + case CameraEventType::Disconnect: + if (value) { + camera->disconnected.connect(camera.get(), [cm = this->shared_from_this(), camera]() { + cm->handleDisconnected(camera); + }); + } else { + camera->disconnected.disconnect(); + } + break; + default: + ASSERT(false); + } } void PyCameraManager::writeFd() @@ -116,16 +353,24 @@ int PyCameraManager::readFd() return -EIO; } -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 3574db23..31747547 100644 --- a/src/py/libcamera/py_camera_manager.h +++ b/src/py/libcamera/py_camera_manager.h @@ -13,12 +13,56 @@ using namespace libcamera; -class PyCameraManager +enum class CameraEventType { + 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, + Request *request = nullptr, FrameBuffer *fb = nullptr) + : type_(type), camera_(camera), request_(request), fb_(fb) + { + } + + CameraEventType type_; + std::shared_ptr camera_; + Request *request_; + FrameBuffer *fb_; +}; + +/* + * 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 { + PyCameraEvent(CameraEventType type, pybind11::object camera) + : type_(type), camera_(camera) + { + } + + CameraEventType type_; + pybind11::object camera_; + pybind11::object request_; + pybind11::object fb_; +}; + +class PyCameraManager : public std::enable_shared_from_this { public: PyCameraManager(); ~PyCameraManager(); + void init(); + pybind11::list cameras(); std::shared_ptr get(const std::string &name) { return cameraManager_->get(name); } @@ -26,20 +70,33 @@ 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 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); - void handleRequestCompleted(Request *req); + bool getCameraEventFlag(std::shared_ptr camera, CameraEventType event_type); + void setCameraEventFlag(std::shared_ptr camera, CameraEventType event_type, bool value); 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); + + std::map, uint32_t> camera_event_masks_; }; diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp index 5a5f1a37..981a3070 100644 --- a/src/py/libcamera/py_main.cpp +++ b/src/py/libcamera/py_main.cpp @@ -110,6 +110,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"); @@ -136,12 +137,27 @@ PYBIND11_MODULE(_libcamera, m) m.def("log_set_level", &logSetLevel); /* Classes */ + + py::enum_(pyEvent, "Type") + .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(); if (!cm) { cm = std::make_shared(); + cm->init(); gCameraManager = cm; } @@ -153,10 +169,33 @@ 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); pyCamera .def_property_readonly("id", &Camera::id) + + .def("get_camera_event_enabled", + [](Camera &self, CameraEventType type) { + auto cm = gCameraManager.lock(); + return cm->getCameraEventFlag(self.shared_from_this(), type); + }) + + .def("enable_camera_event", + [](Camera &self, CameraEventType type) { + auto cm = gCameraManager.lock(); + cm->setCameraEventFlag(self.shared_from_this(), type, true); + }) + + .def("disable_camera_event", + [](Camera &self, CameraEventType type) { + auto cm = gCameraManager.lock(); + cm->setCameraEventFlag(self.shared_from_this(), type, false); + }) + .def("acquire", [](Camera &self) { int ret = self.acquire(); if (ret) @@ -173,11 +212,6 @@ PYBIND11_MODULE(_libcamera, m) const std::unordered_map &controls) { /* \todo What happens if someone calls start() multiple times? */ - auto cm = gCameraManager.lock(); - ASSERT(cm); - - self.requestCompleted.connect(cm.get(), &PyCameraManager::handleRequestCompleted); - ControlList controlList(self.controls()); for (const auto &[id, obj] : controls) { @@ -187,7 +221,6 @@ PYBIND11_MODULE(_libcamera, m) int ret = self.start(&controlList); if (ret) { - self.requestCompleted.disconnect(); throw std::system_error(-ret, std::generic_category(), "Failed to start camera"); } @@ -196,11 +229,16 @@ PYBIND11_MODULE(_libcamera, m) .def("stop", [](Camera &self) { int ret = self.stop(); - self.requestCompleted.disconnect(); + auto cm = gCameraManager.lock(); + ASSERT(cm); + + auto events = cm->getPyCameraEvents(self.shared_from_this()); if (ret) throw std::system_error(-ret, std::generic_category(), "Failed to stop camera"); + + return events; }) .def("__str__", [](Camera &self) { From patchwork Sat Jun 3 07:56:06 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 18689 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 22E73C32AA for ; Sat, 3 Jun 2023 07:57:18 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id F37046288D; Sat, 3 Jun 2023 09:57:16 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1685779037; bh=9HixovCG5rJ3dB8lCPbW0/trjk63jicDwxhovla84yA=; 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=fXFZ4CwQO1VNMMFRXK4BTBQ3vanNnQU36fQsoQv5HEusNEz95prbTNCiYtWUIrjsB 5J5zLR+ldcQXOMU+OyC8ZI+gRK31mF5x0KTBbZvTd1Rkks6JSibIcQRQOFAgtPg31E JD5kjp15BgigoFfy+g1sfdZId8SqINlf9o2ZUYo1jQVt+c4sa0XFodCU+HJYY5/70W ud6/eP5abuBPEQoCpCIKrBBUE3a4QQpz9bKWnfI5SY8+06roLppqBUjGEBHTzLozNs NWQRNP3osP55AhTOGLMMgr2uff/gT7py/f10wU5g2GW8kfQn5uehBF+lo1GNOZdlhG 7yy6YlcARaPHQ== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 6E4CF62728 for ; Sat, 3 Jun 2023 09:57:11 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="KilaxKSI"; dkim-atps=neutral Received: from desky.lan (91-154-35-171.elisa-laajakaista.fi [91.154.35.171]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 9871C468; Sat, 3 Jun 2023 09:56:47 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1685779008; bh=9HixovCG5rJ3dB8lCPbW0/trjk63jicDwxhovla84yA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=KilaxKSIEOEtCQ0fRJax9WIoUdktS63Sg6XnvLJrGKAseww/kYCup44n3YUF88j/W y42QqxJnX91++1LjBRsyi9+dw18F7WpaL6lSKOtlJQVKv+nuwmgHw7+yvDJyHyU5wL mUMMmWtm0sXYuOZwlRqNsHSI4+1LGXBQoPsBMcxs= To: libcamera-devel@lists.libcamera.org Date: Sat, 3 Jun 2023 10:56:06 +0300 Message-Id: <20230603075615.20663-5-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> References: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 04/13] 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 Reviewed-by: Laurent Pinchart --- src/py/cam/cam.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/py/cam/cam.py b/src/py/cam/cam.py index a2a115c1..1e2d1f69 100755 --- a/src/py/cam/cam.py +++ b/src/py/cam/cam.py @@ -230,11 +230,19 @@ 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) + for ev in self.cm.get_events(): + type = ev.type + + if type == libcam.Event.Type.CameraAdded: + print(f'Camera {ev.camera} added') + elif type == libcam.Event.Type.CameraRemoved: + print(f'Camera {ev.camera} removed') + elif type == libcam.Event.Type.Disconnect: + print(f'Camera {ev.camera} disconnected') + elif type == libcam.Event.Type.RequestCompleted: + self.__request_handler(ev.camera, ev.request) + else: + raise RuntimeError("Bad event type") running = any(ctx.reqs_completed < ctx.opt_capture for ctx in self.contexts) return running @@ -242,7 +250,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)) @@ -447,6 +457,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 Sat Jun 3 07:56:07 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 18690 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 81BBBC3200 for ; Sat, 3 Jun 2023 07:57:18 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 1244A62886; Sat, 3 Jun 2023 09:57:18 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1685779038; bh=kJHjyipMYAIbHcbAZy0LPyQnHVkzeNbGTkQwN4dtcLM=; 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=ky5f7MRsSoVHBzifmm26guUUjSb4IIaena0/rP+VleWwYpSh3hveUwyHAT7WgXVOZ DzNM3MMhWqnRjzR+mSk06RqnxsfJL0UvsrfAsngrdIW6SKtT2IU6b6fdtzqQHxI0Nn va1eEm21pI1A0MTmS+Iph5NFof906fy1T9+rqTZ/+dVn2QSbacSYW3zcZ6K4qH1gVF oxUl7yTg0pP1cq4qnvAB+p1BpPQ0DY7nVNfBk6+iitm7yK80wRvSU8pwXP1+kWgaIu myldGTQoex0pD948/9aISB8L2EXN0yF+71xlgG9PUqXfTT+QaAM4lgDtbYUS7rtPvV eTUwC1XYL5gJQ== 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 C2E886287C for ; Sat, 3 Jun 2023 09:57:11 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="BiLJSbwa"; dkim-atps=neutral Received: from desky.lan (91-154-35-171.elisa-laajakaista.fi [91.154.35.171]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 47507B2A; Sat, 3 Jun 2023 09:56:48 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1685779008; bh=kJHjyipMYAIbHcbAZy0LPyQnHVkzeNbGTkQwN4dtcLM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=BiLJSbwa/pTGVq51Ndblr+pTXrhVLeeCv9BHfhpqudwG9YslGipodnUUf1xrYQzwr bnjmpkRaSTnoTTVL0vOCH52lxX1ig5HegNZNz/232cPaU0bk8mES1EVxRyyOm0J5GJ 2zukweRwo/DIassM8/tlpaRlzibH7UyVFqvTPo6w= To: libcamera-devel@lists.libcamera.org Date: Sat, 3 Jun 2023 10:56:07 +0300 Message-Id: <20230603075615.20663-6-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> References: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 05/13] 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" Update the Python unittests to use the new event model. The unittests expect a controlled environment to be run on, and the tests will fail if we get any other event but RequestCompleted (e.g. camera connected). 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 fe1e8ef0..0c844a20 100755 --- a/test/py/unittests.py +++ b/test/py/unittests.py @@ -217,9 +217,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 @@ -283,9 +283,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 Sat Jun 3 07:56:08 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 18691 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 D11AEC32AB for ; Sat, 3 Jun 2023 07:57:18 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8DB476288E; Sat, 3 Jun 2023 09:57:18 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1685779038; bh=edz4xFWTKtABKI4EC7dWnAxOKJeMyqJxs/BmtaJae4g=; 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=DlInb5l4hNNOD7j7RzKRNvHSB3c3ZDvOFW9KphUZ5kC6wS3JbHebPRZe+JH0IUDQc TZMZ3MK/fuh+mNI7OdKDopT/9z9pzvv102Egtetm2tKDqEEnRkfjoWRhayOBZ1KTHN 4KPktxsJKLOvQOvc4B6MEmDaBkx0LfeacDmXVuIgBcVTOJU1GXkAnRFh3g1f0ZlGJ/ qxCagljVlacTupF904fVERzpFhUv/6AYCNgqla9gii04vPfNu4hOygyLru8a7GPYqR bZj/FTyqfp+hoNFC8KriU6P81SvUHq2MkJ/N9yDYA+uB3W3D14LPNpzSiDepOIMuiN /MstL5n4xGMpg== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 73AB662709 for ; Sat, 3 Jun 2023 09:57:12 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="hlKKD5n/"; dkim-atps=neutral Received: from desky.lan (91-154-35-171.elisa-laajakaista.fi [91.154.35.171]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id DAB6E468; Sat, 3 Jun 2023 09:56:48 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1685779009; bh=edz4xFWTKtABKI4EC7dWnAxOKJeMyqJxs/BmtaJae4g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=hlKKD5n/2F2WCYX5KuPItkgme2S4CwUNNQ7mpXjOgFWzvgvj7paovpr2UhWqMw9pP cDwmpMc+EfHltmZzgznuHxPv+J3RM19Qm4NYtxWDHz84f2ZTX4EY6E8nTnPgHkNDQE Js/JEur4XQh4iSn779CBhyOADUiEFC+PAANt/GCc= To: libcamera-devel@lists.libcamera.org Date: Sat, 3 Jun 2023 10:56:08 +0300 Message-Id: <20230603075615.20663-7-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> References: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 06/13] 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" Update simple-capture.py to the new event model. Signed-off-by: Tomi Valkeinen Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/py/examples/simple-capture.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/py/examples/simple-capture.py b/src/py/examples/simple-capture.py index 4b85408f..4fa36d6f 100755 --- a/src/py/examples/simple-capture.py +++ b/src/py/examples/simple-capture.py @@ -107,17 +107,22 @@ 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 - # for a camera event. Here we should almost always get a single - # Request, but in some cases there could be multiple or none. + # 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 + # completion event, but in some cases there could be multiple ones, + # other events, or no events at all. events = sel.select() 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 Sat Jun 3 07:56:09 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 18692 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 50AF6C32AC for ; Sat, 3 Jun 2023 07:57:19 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 105BD627DE; Sat, 3 Jun 2023 09:57:19 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1685779039; bh=ivMAMfY7LAj8Ihu/ud9j0ozVaB9QF6fEIVB/e9R5Ukw=; 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=MUwk/lojioTAaXIbpyuBkAFHVECjJJpajNiFC2ih9dDmDlYY+HV+ZZ2ZgVYrnR/N1 cTQtEWCVfCD0inw8FSmSsyEVhonS8vslcdtR8xhPq4qiX4cRYPVDI2uuV3oUlNcwZE AeQ1mLj7hFq551zviW2c7npqyo2yjjplxiY7mer5mU9di5YwMDKYu5Hz5yfKVeDZgE uz5c4/4iXIZR2Y1NlvBOVIUGnwW3c8qun0JzNA/BidjkOzee5nnW4fsz+WOlozzS2U Us9pK0YF58IDsCYl/Xap9UJXdK2htNPEEB8EHxAUGCcNCVndocZmeyZvCTYnP8i7Qq Kq/XmWnrQ+n3g== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 22588627DE for ; Sat, 3 Jun 2023 09:57:13 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="PcVTimUy"; dkim-atps=neutral Received: from desky.lan (91-154-35-171.elisa-laajakaista.fi [91.154.35.171]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 8C2B5B2A; Sat, 3 Jun 2023 09:56:49 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1685779010; bh=ivMAMfY7LAj8Ihu/ud9j0ozVaB9QF6fEIVB/e9R5Ukw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=PcVTimUy+ILCWLuyNmex81fN2grO5z4tif7JAZOgPxnj9aTgob2PF1kpx6s8ICj4I AdfTUcNJcSIRWK5M5HYXCgW0+Ummw4lEXwWBALc6ZAh3MZhBLzBfpDTbT6tDrjk+vA D2By8WR1S62YYdl8uBZwjmCjaBVMZJa9/TZx3/t4= To: libcamera-devel@lists.libcamera.org Date: Sat, 3 Jun 2023 10:56:09 +0300 Message-Id: <20230603075615.20663-8-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> References: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 07/13] 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" Update simple-continuous-capture.py to the new event model. 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..37ca623c 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 be a single RequestCompleted event, but in some cases + # there could be multiple ones, other events, or no events at all. - 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 Sat Jun 3 07:56:10 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 18693 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 DA5FFC328F for ; Sat, 3 Jun 2023 07:57:19 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 937F26278F; Sat, 3 Jun 2023 09:57:19 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1685779039; bh=iaRylJ5l1sFUWopCwUojy8cIUA0Y2r4I2IXZHJH+WuA=; 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=f/3O9ePuRb5/s0zUC2iK5n4eIGihoWDbJrbM/ek8YGPou0KBEYAtN075vdHlc7dNG N9roYRNwRA77+68rIUrNxIwYTwKOKFRd9FWN5dcRLO6zGnjUvxwvvigafJYHpIuhS+ aaXkNANZy9lxVtjQgtL/AtyeFOT3jyQm+OBFhKHm6i68rTJJKT5xm/uCS4FDKnvZ7u E0Z7TUSwbL4P4BTY9Uv4x30Hg23LLvSqKCetDdmLR3b0YjryxoTsCZDIzsnElCR8CM GEiHawwdvWfXqRhWspxuhwrx3+tc6XZ7JKykvILORbc+uYC80cwXsN+//LN3MeAYrs WcDQuGtB/+cIA== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id C094962885 for ; Sat, 3 Jun 2023 09:57:13 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="MRx3syON"; dkim-atps=neutral Received: from desky.lan (91-154-35-171.elisa-laajakaista.fi [91.154.35.171]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 39AF0468; Sat, 3 Jun 2023 09:56:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1685779010; bh=iaRylJ5l1sFUWopCwUojy8cIUA0Y2r4I2IXZHJH+WuA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MRx3syONFmePRqQc2z8fOHaWDGvCztRBb8Pppp96XQwj57rOnPsMgxJUGH2EDseik MnBpDLm1yS54+mT5HzH2Zdp0UU4B4vOVlM7J+Z/aHfZFUOjE8hA0eIv4I2XfrgD+Ot 2WfZ7iSG5Q9EVJzlZzE5SW3bKNRpc91m7fQyAqCc= To: libcamera-devel@lists.libcamera.org Date: Sat, 3 Jun 2023 10:56:10 +0300 Message-Id: <20230603075615.20663-9-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> References: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 08/13] 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" Update simple-cam.py to the new event model. Signed-off-by: Tomi Valkeinen Reviewed-by: Jacopo Mondi Reviewed-by: Laurent Pinchart --- src/py/examples/simple-cam.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/py/examples/simple-cam.py b/src/py/examples/simple-cam.py index 1cd1019d..2d359cb7 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 be a single RequestCompleted event, but in some cases + # there could be multiple ones, other events, or no events at all. - 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): @@ -304,7 +305,7 @@ def main(): # CameraManager and an event will be raised using eventfd. # # The list of completed Requests can be retrieved with - # CameraManager.get_ready_requests(), which will also clear the list in the + # CameraManager.get_events(), which will also clear the list in the # CameraManager. # # The eventfd can be retrieved from CameraManager.event_fd, and the fd can From patchwork Sat Jun 3 07:56:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 18694 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 D21C1C32AD for ; Sat, 3 Jun 2023 07:57:20 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 84A4962885; Sat, 3 Jun 2023 09:57:20 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1685779040; bh=wYbL/tGfOiTWpYkSunmxUHnRx/GsiUaGPhOYCs/HAqE=; 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=Y4z2bgn3J/u76w0LvAd88INAFPP4GhGjqO6ceVv9wB7MknzREwtXkh7JhoIt4HCvp hHnsd4TEYfJGVXEc53BgEUyKdVuUed299F3tKcWm0FbcM9iBu740oY1E/q29i040cI LraewgasQMoxtSl3cB0V4u387vXCbEkfE3IN/EPCEF67edpcsCXOBNdovbb4V6Tmzp 9YH4g08lfsu/T3M/JvpNHqBRL/3OWbqG62RaCU+Q5LFV6xtvbUazZFX/w3oTdrSugp tqRJJsJc7tPwBZZjhDi/iSaf2q3lb/gPJFIkeLNPDi3vUNmJ3lZWTzdG9xcU3PjY5i sT6xhVC7EVSrA== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 602DF6287E for ; Sat, 3 Jun 2023 09:57:14 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="cGuuQZ8+"; dkim-atps=neutral Received: from desky.lan (91-154-35-171.elisa-laajakaista.fi [91.154.35.171]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id DC363B2A; Sat, 3 Jun 2023 09:56:50 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1685779011; bh=wYbL/tGfOiTWpYkSunmxUHnRx/GsiUaGPhOYCs/HAqE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cGuuQZ8+oNmgguFklf07FH8VUC+tBN9bM4+lQFscy4VttjWy7CaKB99Ht78f5s43v dPdJ5HMvWFABsJ3WOHXwp/1h+tX7qvznFETFpGMmSqv0GC4ZfUFsbRZAu4RSswnsBt pFr+OOciFwKwXLDk3MBg2Z40iVZrMhzu/AK82ZZU= To: libcamera-devel@lists.libcamera.org Date: Sat, 3 Jun 2023 10:56:11 +0300 Message-Id: <20230603075615.20663-10-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> References: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 09/13] py: Drop get_ready_requests() 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" get_ready_requests() is deprecated, and the Python code in libcamera has been converted to the new event system, so we can drop get_ready_requests(). Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- src/py/libcamera/py_camera_manager.cpp | 24 ------------------------ src/py/libcamera/py_camera_manager.h | 1 - src/py/libcamera/py_main.cpp | 3 --- 3 files changed, 28 deletions(-) diff --git a/src/py/libcamera/py_camera_manager.cpp b/src/py/libcamera/py_camera_manager.cpp index 83c2b063..4f3a59a3 100644 --- a/src/py/libcamera/py_camera_manager.cpp +++ b/src/py/libcamera/py_camera_manager.cpp @@ -110,30 +110,6 @@ PyCameraEvent PyCameraManager::convertEvent(const CameraEvent &event) return pyevent; } -/* DEPRECATED */ -std::vector PyCameraManager::getReadyRequests() -{ - int ret = readFd(); - - if (ret == -EAGAIN) - return std::vector(); - - if (ret != 0) - throw std::system_error(-ret, std::generic_category()); - - std::vector py_reqs; - - 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(); diff --git a/src/py/libcamera/py_camera_manager.h b/src/py/libcamera/py_camera_manager.h index 31747547..46121a78 100644 --- a/src/py/libcamera/py_camera_manager.h +++ b/src/py/libcamera/py_camera_manager.h @@ -70,7 +70,6 @@ public: int eventFd() const { return eventFd_.get(); } - std::vector getReadyRequests(); /* DEPRECATED */ std::vector getPyEvents(); std::vector getPyCameraEvents(std::shared_ptr camera); diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp index 981a3070..bc40849a 100644 --- a/src/py/libcamera/py_main.cpp +++ b/src/py/libcamera/py_main.cpp @@ -170,9 +170,6 @@ PYBIND11_MODULE(_libcamera, m) .def_property_readonly("event_fd", &PyCameraManager::eventFd) - /* DEPRECATED */ - .def("get_ready_requests", &PyCameraManager::getReadyRequests) - .def("get_events", &PyCameraManager::getPyEvents); pyCamera From patchwork Sat Jun 3 07:56:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 18695 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 778F6C32AA for ; Sat, 3 Jun 2023 07:57:21 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 168C7626FA; Sat, 3 Jun 2023 09:57:21 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1685779041; bh=cAWEa3NfkVrbPYoK1a6BVS1X1Z4HPm6BjAhCUj9LxvE=; 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=yxGTIa4g56l4Qig53E5gcYEfwtzVn40UtqpPR9oS6vLMtv3kTVF79hcSvzWwzA4Uj D3S1pQjcKxCIOBBtA5JLDOJGaehP2JRoZZVNLlQ3fMfOvxRlmhw3pcvAmKkHzsxtgt EKbWg3WAiMhJXYd5wKfXv2UyIFUM+QidvsbpN4Hw3IVs4zuq4Drpsi9AhvLl8gNu5P tWlCvh0lJobH+ExVDL/tEikmI/IC9hNjMWqUGA7drBYeAzC8Cotj7GLt46922oJmZO nYpuPgiEoxw2yPfY0/IXqFxlacndMYIEdjBO5lYDn4x5jJ7k5o03V0FtP3520OlaHL uEwGbI739Bm1g== 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 F1EC56287F for ; Sat, 3 Jun 2023 09:57:14 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="ZuIBQlVE"; dkim-atps=neutral Received: from desky.lan (91-154-35-171.elisa-laajakaista.fi [91.154.35.171]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 798DD468; Sat, 3 Jun 2023 09:56:51 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1685779011; bh=cAWEa3NfkVrbPYoK1a6BVS1X1Z4HPm6BjAhCUj9LxvE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZuIBQlVELOalRw3/SWukS6J+om2ESeP8WrSockLvaGHJ2D08B4ZA5Ulx7FECMkPlK e7GSwZywsrVDeopm0dTE85CXvlVzmbDK2RHS21boVjRZmJhEatspoNOKlgScZJmnnZ gQq9CuxvyGf1H0CjVQNFipdqnW8W+iBMIDuTxFy8= To: libcamera-devel@lists.libcamera.org Date: Sat, 3 Jun 2023 10:56:12 +0300 Message-Id: <20230603075615.20663-11-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> References: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 10/13] 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 100755 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 100755 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()) From patchwork Sat Jun 3 07:56:13 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 18696 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 67A9DC3200 for ; Sat, 3 Jun 2023 07:57:22 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E017862896; Sat, 3 Jun 2023 09:57:21 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1685779041; bh=xnsU+dBTrM++WqFLAtAgLiiKiQrid4kqBDwvRdKooBA=; 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=u45RAwiTEFc6Jj1MK5/1qtNaV7r1RWfeZ3la+9B92eu4gk2cSZAJyT7zDIXSbqW8N huWdhmX8fGNb27zr1r1Pv5nedyXhNNdxxS+pUg5qygL/vidD+iduno9MpOMHOgvpWB HkRaMcauN7yV53aol6jTsx+818ulP6hfOsK2Aez5MN0R/+zDYJJNqsiobEaTVB0k6g fo4rLPXkdWyiWteh6fGaWeP7v1JA3KG4Ryqgo8tBdDUB2i239Mb3PEmMn77WIp0JSW afsxhBdIYDzv3fUVwh8//kCjR/No+sJBwQYxEQXwP9yuuKQqUP9eN26ZqZAIlJ36Or 2yMmcEIxJyJKw== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8F76F62709 for ; Sat, 3 Jun 2023 09:57:15 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="NhaF/WZy"; dkim-atps=neutral Received: from desky.lan (91-154-35-171.elisa-laajakaista.fi [91.154.35.171]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 1871BB2A; Sat, 3 Jun 2023 09:56:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1685779012; bh=xnsU+dBTrM++WqFLAtAgLiiKiQrid4kqBDwvRdKooBA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=NhaF/WZyL/yCatPWzz3l3yR/RNfJhbvkoPpcO1BlYbekr+IOZrnEYr/W4NiBOQvPj cFTUyP/PDyyqBx2XsjRIpQju3CiYSMePUz7ccOugeua1JuRyMm4KcIqX+ijGZ6bS1q 3KftdmDGTt7gfngpFTqmUC+qDaj5gq+ihMvgRaug= To: libcamera-devel@lists.libcamera.org Date: Sat, 3 Jun 2023 10:56:13 +0300 Message-Id: <20230603075615.20663-12-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> References: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 11/13] py: unittests.py: Add test for refs & keep-alives 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 test for references and keep-alives by doing a capture, reusing the Requests once and testing that the objects are freed as soon as all the refs and keep-alives are gone. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- test/py/unittests.py | 128 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/test/py/unittests.py b/test/py/unittests.py index 0c844a20..024d9752 100755 --- a/test/py/unittests.py +++ b/test/py/unittests.py @@ -31,6 +31,134 @@ class BaseTestCase(unittest.TestCase): self.assertTrue(all([not wr() for wr in wr_list]), msg) +# Test references and keep-alives by doing a capture, reusing the Requests once +# and testing that the objects are freed as soon as all the refs and keep-alives +# are gone. +class CaptureRefTestMethods(BaseTestCase): + def test_ref(self): + cm = libcam.CameraManager.singleton() + wr_cm = weakref.ref(cm) + + cam = cm.get('platform/vimc.0 Sensor B') + self.assertIsNotNone(cam) + wr_cam = weakref.ref(cam) + + cam.acquire() + + camconfig = cam.generate_configuration([libcam.StreamRole.StillCapture]) + self.assertTrue(camconfig.size == 1) + wr_camconfig = weakref.ref(camconfig) + + streamconfig = camconfig.at(0) + wr_streamconfig = weakref.ref(streamconfig) + + cam.configure(camconfig) + + stream = streamconfig.stream + wr_stream = weakref.ref(stream) + + # stream keeps streamconfig and camconfig alive + del streamconfig + del camconfig + gc.collect() + self.assertIsAlive(wr_camconfig) + self.assertIsAlive(wr_streamconfig) + + allocator = libcam.FrameBufferAllocator(cam) + num_bufs = allocator.allocate(stream) + self.assertTrue(num_bufs > 0) + wr_allocator = weakref.ref(allocator) + + buffers = allocator.buffers(stream) + self.assertIsNotNone(buffers) + + wr_buffers = [weakref.ref(b) for b in buffers] + + del allocator + self.assertIsAlive(wr_allocator) + + reqs = [] + wr_reqs = [] + for i in range(num_bufs): + req = cam.create_request(i) + self.assertIsNotNone(req) + + wr_reqs.append(weakref.ref(req)) + + req.add_buffer(stream, buffers[i]) + + reqs.append(req) + + del buffers + del stream + + self.assertIsDead(wr_stream) + + cam.start() + + reqs_target = num_bufs * 2 + reqs_queued = 0 + reqs_captured = 0 + + for req in reqs: + cam.queue_request(req) + reqs_queued += 1 + + del req + del reqs + + # All buffers and reqs should be alive + self.assertIsAllAlive(wr_buffers) + self.assertIsAllAlive(wr_reqs) + + sel = selectors.DefaultSelector() + sel.register(cm.event_fd, selectors.EVENT_READ) + + while True: + events = sel.select() + if not events: + continue + del events + + for ev in cm.get_events(): + self.assertEqual(ev.type, libcam.Event.Type.RequestCompleted) + + reqs_captured += 1 + self.assertLessEqual(reqs_captured, reqs_target) + + if reqs_queued < reqs_target: + req: libcam.Request = typing.cast(libcam.Request, ev.request) + req.reuse() + cam.queue_request(req) + reqs_queued += 1 + del req + + del ev + + if reqs_captured == reqs_target: + break + + del sel + + # The allocator and all buffers and reqs should be dead + self.assertIsAllDead(wr_buffers) + self.assertIsAllDead(wr_reqs) + self.assertIsDead(wr_allocator) + + events = cam.stop() + self.assertZero(len(events)) + del events + cam.release() + + del cm + self.assertIsAlive(wr_cm) + self.assertIsAlive(wr_cam) + + del cam + self.assertIsDead(wr_cam) + self.assertIsDead(wr_cm) + + class SimpleTestMethods(BaseTestCase): def test_get_ref(self): cm = libcam.CameraManager.singleton() From patchwork Sat Jun 3 07:56:14 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 18697 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 D1238C32AE for ; Sat, 3 Jun 2023 07:57:22 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8EE0462897; Sat, 3 Jun 2023 09:57:22 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1685779042; bh=ukPLQkZ7mhOvt8DGT/hHKfTwnq7m5x/13Sc5Rq8R/NE=; 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=YCyTJcDOcPnIVwuFGwu4wbonguHC8q5qc2pDpnELFBuwqk910V2SmNTz4NXV4V0Dg V4Qu1+UOQ7YvfB8rADNudoTA4yVgLx7hbttN5MDyrrQohj08IexYPeQx+5l8OAykYg svXMQTfdpH6fB0OysgOjW1iCmkoSEOh4RD170qhcDBws6tntJtVFgEenX7sxPQ/AZ4 q+Qcoh2aMYEGr+9TRdDI1lh+Vn9ghfG4XvrL0xCyCmFa0e0wIPHFti+CH6n0YX6ihj 7i+crcRbkbKf06PvPSJPTRPgwwyNcFzNRt1Y9NZ5AnCpTUTN3AUoopemwM7o9D2RB4 BOcOvId06gzpw== 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 34B986288B for ; Sat, 3 Jun 2023 09:57:16 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="l3M7Y8wT"; dkim-atps=neutral Received: from desky.lan (91-154-35-171.elisa-laajakaista.fi [91.154.35.171]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id ACE11F07; Sat, 3 Jun 2023 09:56:52 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1685779013; bh=ukPLQkZ7mhOvt8DGT/hHKfTwnq7m5x/13Sc5Rq8R/NE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=l3M7Y8wTAjljUKsmrrQry5FqSkkMJUYYzzy7CJyERagzPpmJyaajY2yzL4q8+v/kZ Mr1Pihr1HFpnOQ9mJ8MdzMKHaROLQ9X1u6RprcDJijiRcED15a+AXaugV2DCj1jQje LrdvYW1DrZ1IzXZRv1zuH8N3rBX0d//mMK2xGO60= To: libcamera-devel@lists.libcamera.org Date: Sat, 3 Jun 2023 10:56:14 +0300 Message-Id: <20230603075615.20663-13-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> References: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 12/13] py: unittests.py: Fix type checker warnings X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Tomi Valkeinen via libcamera-devel From: Tomi Valkeinen Reply-To: Tomi Valkeinen Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Fix type checker warnings by dropping unused imports and using _ for variable names that are not used. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- test/py/unittests.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/py/unittests.py b/test/py/unittests.py index 024d9752..967e791f 100755 --- a/test/py/unittests.py +++ b/test/py/unittests.py @@ -4,11 +4,9 @@ # Copyright (C) 2022, Tomi Valkeinen from collections import defaultdict -import errno import gc import libcamera as libcam import selectors -import time import typing import unittest import weakref @@ -410,7 +408,7 @@ class SimpleCaptureMethods(CameraTesterBase): running = True while running: events = sel.select() - for key, _ in events: + for _ in events: for ev in cm.get_events(): self.assertEqual(ev.type, libcam.Event.Type.RequestCompleted) reqs.append(ev.request) From patchwork Sat Jun 3 07:56:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomi Valkeinen X-Patchwork-Id: 18698 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 3D106C32AF for ; Sat, 3 Jun 2023 07:57:23 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0EC24628A1; Sat, 3 Jun 2023 09:57:23 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1685779043; bh=w/FC3Gju+vqRcQk+qqVpMJf2jHZlmQ8sepFEn0xU0IQ=; 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=XJGUpUUQtOomymBKio0j4qUuLMox8iowadxeeUXmz1VjBxDXcMTc3wzY9KOsU7bIQ O8SpEtWnSMt3UK+RydAKXEeV7BI8nNIMZm7HT/Hsw0jxHiUXdnSOYaZm81JIUyKaNY RZ6lTnSyoHBErdzgPl9SpMhgxdds2jaQU8v5wNPSriaMfwtxFR0W7nH9Y+WiGMAZl/ SjR2twJIiAPWvF+NATzZ0QQxkAAhqZe2vPm256DaXHXfYwd5ISAOUJPFTi/i3zl/tv Mekw1JostEwqXPvLbNLxQf5mgHdK3ranxEu5xadZ8aj9F14dLbrl+9aJL66xaB2xdS Ea7d18/8eX8wg== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B9AFA6287E for ; Sat, 3 Jun 2023 09:57:16 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="ZhPAlRli"; dkim-atps=neutral Received: from desky.lan (91-154-35-171.elisa-laajakaista.fi [91.154.35.171]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 49F6A1AFA; Sat, 3 Jun 2023 09:56:53 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1685779013; bh=w/FC3Gju+vqRcQk+qqVpMJf2jHZlmQ8sepFEn0xU0IQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZhPAlRli4e2/PSUoJjGnY935TyJ7umAo6gFJv0wEJCAvgGLLsqNDOgwEKqQ7pqpON wPiSV4JUDAQBW6aKozMcF7JvfIsA9qLGSeB1EqC86kBHOlgPoGYtxuST04m2ZeX3wj kF8jdksnU+yDylsa4QJg3yYILq/PkuefKmEzVjdk= To: libcamera-devel@lists.libcamera.org Date: Sat, 3 Jun 2023 10:56:15 +0300 Message-Id: <20230603075615.20663-14-tomi.valkeinen@ideasonboard.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> References: <20230603075615.20663-1-tomi.valkeinen@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v5 13/13] py: Improve stub type generation for PyCameraEvent 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 store the camera, request and fb fields in PyCameraEvent as py::objects, so that we keep the refs and keep-alives. When we return py::objects to the Python side, they, obviously, show up as "objects" when the stub generation is looking at the fields. Fix this by manually casting the py::objects to the correct C++ counterparts, which causes pybind11 to assign the correct types for the properties, helping stubgen to generate correct types. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart --- src/py/libcamera/py_main.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp index bc40849a..85303d71 100644 --- a/src/py/libcamera/py_main.cpp +++ b/src/py/libcamera/py_main.cpp @@ -145,11 +145,19 @@ PYBIND11_MODULE(_libcamera, m) .value("RequestCompleted", CameraEventType::RequestCompleted) .value("BufferCompleted", CameraEventType::BufferCompleted); + /* + * For camera, request and fb fields, manually typecast to the C++ type, + * so that pybind11 assigns the actual type for the return value. This + * makes the stubs generated by pybind11-stubgen contain the correct type, + * instead of "object". + * + * Maybe there's a better way to do this... + */ pyEvent .def_readonly("type", &PyCameraEvent::type_) - .def_readonly("camera", &PyCameraEvent::camera_) - .def_readonly("request", &PyCameraEvent::request_) - .def_readonly("fb", &PyCameraEvent::fb_); + .def_property_readonly("camera", [](PyCameraEvent &self) { return self.camera_.cast(); }) + .def_property_readonly("request", [](PyCameraEvent &self) { return self.request_.cast(); }) + .def_property_readonly("fb", [](PyCameraEvent &self) { return self.fb_.cast(); }); pyCameraManager .def_static("singleton", []() {