{"id":18376,"url":"https://patchwork.libcamera.org/api/patches/18376/?format=json","web_url":"https://patchwork.libcamera.org/patch/18376/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20230309142601.70556-16-tomi.valkeinen@ideasonboard.com>","date":"2023-03-09T14:26:01","name":"[libcamera-devel,v4,15/15] py: Hack for different event enable mechanism","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"7926c2753507b18152b4c6091b12baeb9009af6b","submitter":{"id":109,"url":"https://patchwork.libcamera.org/api/people/109/?format=json","name":"Tomi Valkeinen","email":"tomi.valkeinen@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/18376/mbox/","series":[{"id":3796,"url":"https://patchwork.libcamera.org/api/series/3796/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=3796","date":"2023-03-09T14:25:46","name":"py: New python bindings event handling","version":4,"mbox":"https://patchwork.libcamera.org/series/3796/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/18376/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/18376/checks/","tags":{},"headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id CD191C32A6\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  9 Mar 2023 14:26:31 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 6EDB062718;\n\tThu,  9 Mar 2023 15:26:31 +0100 (CET)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 590A6626D8\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  9 Mar 2023 15:26:22 +0100 (CET)","from desky.lan (91-154-32-225.elisa-laajakaista.fi [91.154.32.225])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id E537E886;\n\tThu,  9 Mar 2023 15:26:21 +0100 (CET)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1678371991;\n\tbh=H9Z7KLUXihKcr8UogM/YAwzpdvBQoIgZwip8xyxiUKE=;\n\th=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:\n\tFrom;\n\tb=Von8tyngRaZVFLcngtTJdmZ0M2Hbu17JNoatDm70T8uK2BQUtDdt/0l1OQX+GLPf9\n\tRjc9joTVONTAbx3NXxPvAmzMqAGEtyAb1+1F652cARWzPGJWzC3DTBh3QLQIqfp7k8\n\t0kg8+HUA2AMFS/6UbgpA2R0T9oPIAlXrKV+K3u/OfxtmAdeVKYUoK30FzoWYPKECi6\n\tV4PXmeSI0c5Ny2ZTJOYqTUDvnKaMdddUqzX9vUFpoIflBAULEqTVabCsKUl/VLrqrF\n\tlz2okTvComplWE5GA1lwaEnRcA/myHD981l3FNY1xI3RwZOg0P5NCRJ/uM7a/a2Ae0\n\tSky/+l3E+ihAw==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1678371982;\n\tbh=H9Z7KLUXihKcr8UogM/YAwzpdvBQoIgZwip8xyxiUKE=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=AAx2kdGru3mqqccaOtY9QEJFeJfp13kOxUYv5gX7lxTpw81IdqQfiFuOl6eWNeWJn\n\tF8m9sJFHLrYp+SDlJTKrD71FjzOyAPVH1QCj68vGk6yjHvJLkSR149VqEextn0xOU1\n\tIxH6nm/75SkW3LQf10OsJ+Mq8CmdZwyj5PqpDGcA="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"AAx2kdGr\"; dkim-atps=neutral","To":"libcamera-devel@lists.libcamera.org","Date":"Thu,  9 Mar 2023 16:26:01 +0200","Message-Id":"<20230309142601.70556-16-tomi.valkeinen@ideasonboard.com>","X-Mailer":"git-send-email 2.34.1","In-Reply-To":"<20230309142601.70556-1-tomi.valkeinen@ideasonboard.com>","References":"<20230309142601.70556-1-tomi.valkeinen@ideasonboard.com>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","Subject":"[libcamera-devel] [PATCH v4 15/15] py: Hack for different event\n\tenable mechanism","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","From":"Tomi Valkeinen via libcamera-devel\n\t<libcamera-devel@lists.libcamera.org>","Reply-To":"Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"Instead of connecting all the event signals automatically (except\nbufferCompletedEvent), add properties to Camera object to enable/disable\nthe events. E.g.\n\ncam.requestCompletedEnabled = True\n\nwould enable the delivery of request completed events.\n\nAlso, as (I think) almost everyone wants request completed events,\nsubscribe to them automatically for all cameras when creating the\nPyCameraManager singleton. If someone doesn't want request completed\nevents, they can set the cam.requestCompletedEnabled to False.\n\nThis is just a quick hack, a proper implementation would need a bit more\nabstraction functionality to the PyCameraManager.\n\nSigned-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>\n---\n src/py/libcamera/py_camera_manager.cpp |   3 -\n src/py/libcamera/py_camera_manager.h   |   5 +-\n src/py/libcamera/py_main.cpp           | 113 ++++++++++++++++++++-----\n 3 files changed, 96 insertions(+), 25 deletions(-)","diff":"diff --git a/src/py/libcamera/py_camera_manager.cpp b/src/py/libcamera/py_camera_manager.cpp\nindex c3b9646f..ca0f6f7a 100644\n--- a/src/py/libcamera/py_camera_manager.cpp\n+++ b/src/py/libcamera/py_camera_manager.cpp\n@@ -182,9 +182,6 @@ std::vector<PyCameraEvent> PyCameraManager::getPyCameraEvents(std::shared_ptr<Ca\n /* Note: Called from another thread */\n void PyCameraManager::handleBufferCompleted(std::shared_ptr<Camera> cam, Request *req, FrameBuffer *fb)\n {\n-\tif (!bufferCompletedEventActive_)\n-\t\treturn;\n-\n \tCameraEvent ev(CameraEventType::BufferCompleted, cam, req, fb);\n \n \tpushEvent(ev);\ndiff --git a/src/py/libcamera/py_camera_manager.h b/src/py/libcamera/py_camera_manager.h\nindex 648d78af..41105de7 100644\n--- a/src/py/libcamera/py_camera_manager.h\n+++ b/src/py/libcamera/py_camera_manager.h\n@@ -77,10 +77,11 @@ public:\n \tvoid handleCameraAdded(std::shared_ptr<Camera> cam);\n \tvoid handleCameraRemoved(std::shared_ptr<Camera> cam);\n \n-\tbool bufferCompletedEventActive_ = false;\n+\tuint32_t event_mask_;\n+\tstd::map<std::shared_ptr<Camera>, uint32_t> camera_event_masks_;\n+\tstd::unique_ptr<CameraManager> cameraManager_;\n \n private:\n-\tstd::unique_ptr<CameraManager> cameraManager_;\n \n \tUniqueFD eventFd_;\n \tlibcamera::Mutex eventsMutex_;\ndiff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp\nindex cb7088b1..54b58366 100644\n--- a/src/py/libcamera/py_main.cpp\n+++ b/src/py/libcamera/py_main.cpp\n@@ -48,6 +48,57 @@ void init_py_geometry(py::module &m);\n void init_py_properties_generated(py::module &m);\n void init_py_transform(py::module &m);\n \n+static bool py_camera_get_event_flag(std::shared_ptr<Camera> camera, CameraEventType event_type)\n+{\n+\tconst uint32_t evbit = 1 << (uint32_t)event_type;\n+\n+\tauto cm = gCameraManager.lock();\n+\tASSERT(cm);\n+\n+\tauto it = cm->camera_event_masks_.find(camera);\n+\n+\tuint32_t mask = 0;\n+\n+\tif (it != cm->camera_event_masks_.end())\n+\t\tmask = it->second;\n+\n+\treturn !!(mask & evbit);\n+}\n+\n+static void py_camera_set_event_flag(std::shared_ptr<Camera> camera, CameraEventType event_type, bool value)\n+{\n+\tconst uint32_t evbit = 1 << (uint32_t)event_type;\n+\n+\tauto cm = gCameraManager.lock();\n+\tASSERT(cm);\n+\n+\tuint32_t mask = 0;\n+\n+\tauto it = cm->camera_event_masks_.find(camera);\n+\tif (it != cm->camera_event_masks_.end())\n+\t\tmask = it->second;\n+\n+\tbool old_val = !!(mask & evbit);\n+\n+\tif (old_val == value)\n+\t\treturn;\n+\n+\tif (value)\n+\t\tmask |= evbit;\n+\telse\n+\t\tmask &= ~evbit;\n+\n+\tcm->camera_event_masks_[camera] = mask;\n+\n+\tif (value) {\n+\t\tcamera->requestCompleted.connect(camera.get(), [cm, camera](Request *req) {\n+\t\t\tcm->handleRequestCompleted(camera, req);\n+\t\t});\n+\t} else {\n+\t\tcamera->requestCompleted.disconnect();\n+\t}\n+}\n+\n PYBIND11_MODULE(_libcamera, m)\n {\n \tinit_py_enums(m);\n@@ -121,6 +172,10 @@ PYBIND11_MODULE(_libcamera, m)\n \t\t\tif (!cm) {\n \t\t\t\tcm = std::make_shared<PyCameraManager>();\n \t\t\t\tgCameraManager = cm;\n+\n+\t\t\t\t/* Always enable RequestCompleted for all cameras */\n+\t\t\t\tfor (auto cam : cm->cameraManager_->cameras())\n+\t\t\t\t\tpy_camera_set_event_flag(cam, CameraEventType::RequestCompleted, true);\n \t\t\t}\n \n \t\t\treturn cm;\n@@ -132,12 +187,47 @@ PYBIND11_MODULE(_libcamera, m)\n \n \t\t.def_property_readonly(\"event_fd\", &PyCameraManager::eventFd)\n \n-\t\t.def(\"get_events\", &PyCameraManager::getPyEvents)\n-\n-\t\t.def_readwrite(\"buffer_completed_active\", &PyCameraManager::bufferCompletedEventActive_);\n+\t\t.def(\"get_events\", &PyCameraManager::getPyEvents);\n \n \tpyCamera\n \t\t.def_property_readonly(\"id\", &Camera::id)\n+\n+\t\t.def_property(\n+\t\t\t\"requestCompletedEnabled\",\n+\t\t\t[](Camera &self) {\n+\t\t\t\treturn py_camera_get_event_flag(self.shared_from_this(),\n+\t\t\t\t\t\t\t\tCameraEventType::RequestCompleted);\n+\t\t\t},\n+\t\t\t[](Camera &self, bool val) {\n+\t\t\t\tpy_camera_set_event_flag(self.shared_from_this(),\n+\t\t\t\t\t\t\t CameraEventType::RequestCompleted,\n+\t\t\t\t\t\t\t val);\n+\t\t\t})\n+\n+\t\t.def_property(\n+\t\t\t\"bufferCompletedEnabled\",\n+\t\t\t[](Camera &self) {\n+\t\t\t\treturn py_camera_get_event_flag(self.shared_from_this(),\n+\t\t\t\t\t\t\t\tCameraEventType::BufferCompleted);\n+\t\t\t},\n+\t\t\t[](Camera &self, bool val) {\n+\t\t\t\tpy_camera_set_event_flag(self.shared_from_this(),\n+\t\t\t\t\t\t\t CameraEventType::BufferCompleted,\n+\t\t\t\t\t\t\t val);\n+\t\t\t})\n+\n+\t\t.def_property(\n+\t\t\t\"disconnectEnabled\",\n+\t\t\t[](Camera &self) {\n+\t\t\t\treturn py_camera_get_event_flag(self.shared_from_this(),\n+\t\t\t\t\t\t\t\tCameraEventType::Disconnect);\n+\t\t\t},\n+\t\t\t[](Camera &self, bool val) {\n+\t\t\t\tpy_camera_set_event_flag(self.shared_from_this(),\n+\t\t\t\t\t\t\t CameraEventType::Disconnect,\n+\t\t\t\t\t\t\t val);\n+\t\t\t})\n+\n \t\t.def(\"acquire\", [](Camera &self) {\n \t\t\tint ret = self.acquire();\n \t\t\tif (ret)\n@@ -157,18 +247,6 @@ PYBIND11_MODULE(_libcamera, m)\n \t\t\tauto cm = gCameraManager.lock();\n \t\t\tASSERT(cm);\n \n-\t\t\tself.requestCompleted.connect(&self, [cm, camera=self.shared_from_this()](Request *req) {\n-\t\t\t\tcm->handleRequestCompleted(camera, req);\n-\t\t\t});\n-\n-\t\t\tself.bufferCompleted.connect(&self, [cm, camera=self.shared_from_this()](Request *req, FrameBuffer *fb) {\n-\t\t\t\tcm->handleBufferCompleted(camera, req, fb);\n-\t\t\t});\n-\n-\t\t\tself.disconnected.connect(&self, [cm, camera=self.shared_from_this()]() {\n-\t\t\t\tcm->handleDisconnected(camera);\n-\t\t\t});\n-\n \t\t\tControlList controlList(self.controls());\n \n \t\t\tfor (const auto& [id, obj]: controls) {\n@@ -178,7 +256,6 @@ PYBIND11_MODULE(_libcamera, m)\n \n \t\t\tint ret = self.start(&controlList);\n \t\t\tif (ret) {\n-\t\t\t\tself.requestCompleted.disconnect();\n \t\t\t\tthrow std::system_error(-ret, std::generic_category(),\n \t\t\t\t\t\t\t\"Failed to start camera\");\n \t\t\t}\n@@ -187,10 +264,6 @@ PYBIND11_MODULE(_libcamera, m)\n \t\t.def(\"stop\", [](Camera &self) {\n \t\t\tint ret = self.stop();\n \n-\t\t\tself.requestCompleted.disconnect();\n-\t\t\tself.bufferCompleted.disconnect();\n-\t\t\tself.disconnected.disconnect();\n-\n \t\t\tauto cm = gCameraManager.lock();\n \t\t\tASSERT(cm);\n \n","prefixes":["libcamera-devel","v4","15/15"]}