[{"id":26611,"web_url":"https://patchwork.libcamera.org/comment/26611/","msgid":"<db13a460-ae6c-f666-949a-97439e264778@ideasonboard.com>","date":"2023-03-09T15:40:10","subject":"Re: [libcamera-devel] [PATCH v4 15/15] py: Hack for different event\n\tenable mechanism","submitter":{"id":109,"url":"https://patchwork.libcamera.org/api/people/109/","name":"Tomi Valkeinen","email":"tomi.valkeinen@ideasonboard.com"},"content":"On 09/03/2023 16:26, Tomi Valkeinen wrote:\n> Instead of connecting all the event signals automatically (except\n> bufferCompletedEvent), add properties to Camera object to enable/disable\n> the events. E.g.\n> \n> cam.requestCompletedEnabled = True\n> \n> would enable the delivery of request completed events.\n> \n> Also, as (I think) almost everyone wants request completed events,\n> subscribe to them automatically for all cameras when creating the\n> PyCameraManager singleton. If someone doesn't want request completed\n> events, they can set the cam.requestCompletedEnabled to False.\n> \n> This is just a quick hack, a proper implementation would need a bit more\n> abstraction functionality to the PyCameraManager.\n\nAlso, the Camera Manager events (camera added/removed) are still always \nconnected. We could add similar properties to enable/disable those.\n\n  Tomi\n\n> Signed-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(-)\n> \n> diff --git a/src/py/libcamera/py_camera_manager.cpp b/src/py/libcamera/py_camera_manager.cpp\n> index 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);\n> diff --git a/src/py/libcamera/py_camera_manager.h b/src/py/libcamera/py_camera_manager.h\n> index 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_;\n> diff --git a/src/py/libcamera/py_main.cpp b/src/py/libcamera/py_main.cpp\n> index 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>","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 74FF6BDE17\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  9 Mar 2023 15:40:15 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id CD786626D5;\n\tThu,  9 Mar 2023 16:40:14 +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 6E2DF61ED7\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  9 Mar 2023 16:40:13 +0100 (CET)","from [192.168.1.15] (91-154-32-225.elisa-laajakaista.fi\n\t[91.154.32.225])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 09AF4589\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  9 Mar 2023 16:40:12 +0100 (CET)"],"DKIM-Signature":["v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org;\n\ts=mail; t=1678376414;\n\tbh=+tMCmxhdwmJxQC5teKPzbgOz6WSy7BIB+gwqfFbcrtY=;\n\th=Date:To:References:In-Reply-To:Subject:List-Id:List-Unsubscribe:\n\tList-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:\n\tFrom;\n\tb=NkuLKb388eaL97nclWd8Z324CTdTDIUvod5OyUvnYKksDYRjLc0Q+dmvsDEM4pqq3\n\t0UP5k0HBQyqrd/oua3YOgVC614isUVIab5KmP0umqWt4+b72QZj5B/OkSNmqB30p1z\n\tFrtuLAn7aqxIA04mExug0pealauJX/kDqSPqYkwhug1ZuUNndxIIay02qlYxxPsbRG\n\tcu9PRwCUqxYVLqHiXfLsaUQvM+2fsRKih6f8d7NXF/QzlwvrzQ+y/gfTWvO+dn4djr\n\tYmFiHOs62MhNitGlKv6KD+GQQWoRiahAwe85swje/2OsXpmR5qzPFBijcFLT+icnCD\n\tBJWEIwQfIuudA==","v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1678376413;\n\tbh=+tMCmxhdwmJxQC5teKPzbgOz6WSy7BIB+gwqfFbcrtY=;\n\th=Date:Subject:To:References:From:In-Reply-To:From;\n\tb=mi9ww9k3bfapkNoLgd7Z6TIqIdlnBvgayTYV1wa3Z1e6qixeYB0SO42NerAkfZ6Ho\n\tglNaQRPkWR3Scc+gUpO09nrwLNIQhSIY5347wihfiy6OcOb9zTXWCCemhcJvdx7Tlg\n\t7gm7/JHzEdmfdUZHazvBtQOPBax+1u2Ccr9jVg5A="],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key; \n\tunprotected) header.d=ideasonboard.com\n\theader.i=@ideasonboard.com\n\theader.b=\"mi9ww9k3\"; dkim-atps=neutral","Message-ID":"<db13a460-ae6c-f666-949a-97439e264778@ideasonboard.com>","Date":"Thu, 9 Mar 2023 17:40:10 +0200","MIME-Version":"1.0","User-Agent":"Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101\n\tThunderbird/102.7.1","Content-Language":"en-US","To":"libcamera-devel@lists.libcamera.org","References":"<20230309142601.70556-1-tomi.valkeinen@ideasonboard.com>\n\t<20230309142601.70556-16-tomi.valkeinen@ideasonboard.com>","In-Reply-To":"<20230309142601.70556-16-tomi.valkeinen@ideasonboard.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"7bit","Subject":"Re: [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>"}}]