Patch Detail
Show a patch.
GET /api/patches/9336/?format=api
{ "id": 9336, "url": "https://patchwork.libcamera.org/api/patches/9336/?format=api", "web_url": "https://patchwork.libcamera.org/patch/9336/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20200817202629.4277-6-email@uajain.com>", "date": "2020-08-17T20:26:40", "name": "[libcamera-devel,v3,5/5] android: camera_hal_manager: Support camera hotplug", "commit_ref": null, "pull_url": null, "state": "accepted", "archived": false, "hash": "a6df91a08eb0d5fcd2a0f2f4469a58bbd2e143e3", "submitter": { "id": 1, "url": "https://patchwork.libcamera.org/api/people/1/?format=api", "name": "Umang Jain", "email": "email@uajain.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/9336/mbox/", "series": [ { "id": 1224, "url": "https://patchwork.libcamera.org/api/series/1224/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=1224", "date": "2020-08-17T20:26:35", "name": "android: Camera hotplug support", "version": 3, "mbox": "https://patchwork.libcamera.org/series/1224/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/9336/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/9336/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 378D6BD87C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 17 Aug 2020 20:26:46 +0000 (UTC)", "from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id DD5A361AEF;\n\tMon, 17 Aug 2020 22:26:45 +0200 (CEST)", "from o1.f.az.sendgrid.net (o1.f.az.sendgrid.net [208.117.55.132])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id F2FBD61AC0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 17 Aug 2020 22:26:41 +0200 (CEST)", "by filterdrecv-p3iad2-5c98798b7-shmb5 with SMTP id\n\tfilterdrecv-p3iad2-5c98798b7-shmb5-18-5F3AE800-6E\n\t2020-08-17 20:26:40.882614427 +0000 UTC m=+359831.957013569", "from mail.uajain.com (unknown)\n\tby ismtpd0008p1maa1.sendgrid.net (SG) with ESMTP id\n\t85Lhv3GpRk6n0ciau08yBQ for <libcamera-devel@lists.libcamera.org>;\n\tMon, 17 Aug 2020 20:26:40.078 +0000 (UTC)" ], "Authentication-Results": "lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=uajain.com header.i=@uajain.com\n\theader.b=\"HFdTLvng\"; dkim-atps=neutral", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=uajain.com;\n\th=from:subject:in-reply-to:references:mime-version:to:cc:\n\tcontent-transfer-encoding:content-type;\n\ts=s1; bh=yiHFIpZQ4kL+dL6weigacL2kbn4cA/MFi6/Usily6/U=;\n\tb=HFdTLvngPllYZl/Yw2DwArTltxsN/PjdQY2/59FDspXr6TopAbF8YEl/jBdKkg05TwCK\n\tw0i9DYfCM4879d/V9ugEdQVofs9sZX6jlOUqq5ARkw060xq8HqKhKKEaOU8S+pnRLEba8H\n\tFkgLmHWl6i+H8Yse/RWxd7zRaJEz+ge/w=", "From": "Umang Jain <email@uajain.com>", "Date": "Mon, 17 Aug 2020 20:26:40 +0000 (UTC)", "Message-Id": "<20200817202629.4277-6-email@uajain.com>", "In-Reply-To": "<20200817202629.4277-1-email@uajain.com>", "References": "<20200817202629.4277-1-email@uajain.com>", "Mime-Version": "1.0", "X-SG-EID": "1Q40EQ7YGir8a9gjSIAdTjhngY657NMk9ckeo4dbHZDiOpywc/L3L9rFqlwE4KPcZj5z9XHfwy1Ge6f/0y1LYwCA/v9XUm1JqRF7ylVeh12n0FwBW8t59CcHJhPITUZXGGGQgUqnsqxj5v/XY65EzXbreL7hK/T92NfH2u0fNm0haQKhw+/XWpW9t8Dqvtln933X7hTQVJuuGGIxxCDhYr+kt0hpLcQVsLlUKj8JSnHX9zVnqGmLm6g+AH9TvPfVcBDra35Xbbr7xiA0TowW4g==", "To": "libcamera-devel@lists.libcamera.org", "Subject": "[libcamera-devel] [PATCH v3 5/5] android: camera_hal_manager:\n\tSupport camera hotplug", "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>", "Content-Type": "text/plain; charset=\"us-ascii\"", "Content-Transfer-Encoding": "7bit", "Errors-To": "libcamera-devel-bounces@lists.libcamera.org", "Sender": "\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>" }, "content": "Extend the support for camera hotplug from libcamera's CameraManager\nto CameraHalManager. Use camera module callbacks to let the framework\nknow about the hotplug events and change the status of cameras being\nbeing hotplugged or unplugged via camera_device_status_change().\n\nIntroduce a map camerasMap_ which book-keeps all cameras seen in the\npast by the CameraHalManager. If the camera is seen for the first time,\na new id is assigned to it. If the camera has been seen before by the\nmanager, it's old id is reused. IDs for internal cameras start with\n'0' and for external cameras, they start with '1000'. Note, for the\ncurrent implementation, we assume all UVC cameras are external cameras.\nAlso, acess to camerasMap_ and cameras_ are protected by a mutex.\n\nSigned-off-by: Umang Jain <email@uajain.com>\n---\n src/android/camera_hal_manager.cpp | 174 +++++++++++++++++++++++++----\n src/android/camera_hal_manager.h | 18 +++\n 2 files changed, 170 insertions(+), 22 deletions(-)", "diff": "diff --git a/src/android/camera_hal_manager.cpp b/src/android/camera_hal_manager.cpp\nindex 3a744af..e851185 100644\n--- a/src/android/camera_hal_manager.cpp\n+++ b/src/android/camera_hal_manager.cpp\n@@ -8,6 +8,7 @@\n #include \"camera_hal_manager.h\"\n \n #include <libcamera/camera.h>\n+#include <libcamera/property_ids.h>\n \n #include \"libcamera/internal/log.h\"\n \n@@ -35,6 +36,7 @@ CameraHalManager::CameraHalManager()\n CameraHalManager::~CameraHalManager()\n {\n \tcameras_.clear();\n+\tcamerasMap_.clear();\n \n \tif (cameraManager_) {\n \t\tcameraManager_->stop();\n@@ -47,6 +49,13 @@ int CameraHalManager::init()\n {\n \tcameraManager_ = new CameraManager();\n \n+\t/* Support camera hotplug. */\n+\tcameraManager_->cameraAdded.connect(this, &CameraHalManager::cameraAdded);\n+\tcameraManager_->cameraRemoved.connect(this, &CameraHalManager::cameraRemoved);\n+\n+\tinternalCameras_ = 0;\n+\texternalCameras_ = 1000;\n+\n \tint ret = cameraManager_->start();\n \tif (ret) {\n \t\tLOG(HAL, Error) << \"Failed to start camera manager: \"\n@@ -56,35 +65,22 @@ int CameraHalManager::init()\n \t\treturn ret;\n \t}\n \n-\t/*\n-\t * For each Camera registered in the system, a CameraDevice\n-\t * gets created here to wraps a libcamera Camera instance.\n-\t *\n-\t * \\todo Support camera hotplug.\n-\t */\n-\tunsigned int index = 0;\n-\tfor (auto &cam : cameraManager_->cameras()) {\n-\t\tstd::shared_ptr<CameraDevice> camera = CameraDevice::create(index, cam);\n-\t\tret = camera->initialize();\n-\t\tif (ret)\n-\t\t\tcontinue;\n-\n-\t\tcameras_.emplace_back(std::move(camera));\n-\t\t++index;\n-\t}\n-\n \treturn 0;\n }\n \n CameraDevice *CameraHalManager::open(unsigned int id,\n \t\t\t\t const hw_module_t *hardwareModule)\n {\n-\tif (id >= numCameras()) {\n+\tMutexLocker locker(mutex_);\n+\n+\tauto iter = cameraIterFromId(id);\n+\tif (iter == cameras_.end()) {\n \t\tLOG(HAL, Error) << \"Invalid camera id '\" << id << \"'\";\n \t\treturn nullptr;\n \t}\n \n-\tCameraDevice *camera = cameras_[id].get();\n+\tCameraDevice *camera = iter->get();\n+\n \tif (camera->open(hardwareModule))\n \t\treturn nullptr;\n \n@@ -93,9 +89,114 @@ CameraDevice *CameraHalManager::open(unsigned int id,\n \treturn camera;\n }\n \n+void CameraHalManager::cameraAdded(std::shared_ptr<Camera> cam)\n+{\n+\tunsigned int id;\n+\tbool isCameraExternal = false;\n+\tbool isCameraNew = false;\n+\n+\tMutexLocker locker(mutex_);\n+\n+\t/*\n+\t * Each camera is assigned a unique integer ID when it is seen for the\n+\t * first time. If the camera has been seen before, the previous ID is\n+\t * re-used and the camera is marked as CAMERA_DEVICE_STATUS_PRESENT\n+\t * subsequently.\n+\t *\n+\t * IDs starts from '0' for internal cameras and '1000' for external\n+\t * cameras.\n+\t */\n+\tauto iter = camerasMap_.find(cam->id());\n+\tif (iter != camerasMap_.end()) {\n+\t\tid = iter->second;\n+\t} else {\n+\t\tisCameraNew = true;\n+\n+\t\t/*\n+\t\t * Now check if this is an external camera and assign\n+\t\t * its id accordingly.\n+\t\t */\n+\t\tconst ControlList &properties = cam->properties();\n+\t\tif (properties.contains(properties::Location) &&\n+\t\t properties.get(properties::Location) ==\n+\t\t properties::CameraLocationExternal) {\n+\t\t\tisCameraExternal = true;\n+\t\t\tid = externalCameras_;\n+\t\t} else {\n+\t\t\tid = internalCameras_;\n+\t\t}\n+\t}\n+\n+\t/*\n+\t * For each Camera registered in the system, a CameraDevice\n+\t * gets created here to wraps a libcamera Camera instance.\n+\t */\n+\tstd::shared_ptr<CameraDevice> camera = CameraDevice::create(id, std::move(cam));\n+\tint ret = camera->initialize();\n+\tif (ret) {\n+\t\tLOG(HAL, Error) << \"Failed to initialize camera: \" << cam->id();\n+\t\treturn;\n+\t}\n+\n+\tif (isCameraNew) {\n+\t\tcamerasMap_.emplace(cam->id(), id);\n+\n+\t\tif (isCameraExternal)\n+\t\t\texternalCameras_++;\n+\t\telse\n+\t\t\tinternalCameras_++;\n+\t}\n+\n+\tcameras_.emplace_back(std::move(camera));\n+\n+\tif (callbacks_)\n+\t\tcallbacks_->camera_device_status_change(callbacks_, id,\n+\t\t\t\t\t\t\tCAMERA_DEVICE_STATUS_PRESENT);\n+\n+\tLOG(HAL, Debug) << \"Camera ID: \" << id << \" added successfully.\";\n+}\n+\n+void CameraHalManager::cameraRemoved(std::shared_ptr<Camera> cam)\n+{\n+\tMutexLocker locker(mutex_);\n+\n+\tauto iter = cameraIterFromCamera(cam.get());\n+\tif (iter == cameras_.end())\n+\t\treturn;\n+\n+\tunsigned int id = (*iter)->id();\n+\tcallbacks_->camera_device_status_change(callbacks_, id,\n+\t\t\t\t\t\tCAMERA_DEVICE_STATUS_NOT_PRESENT);\n+\n+\t/*\n+\t * \\todo Check if the camera is already open and running.\n+\t * Inform the framework about it's absence before deleting it's\n+\t * reference here.\n+\t */\n+\tcameras_.erase(iter);\n+\n+\tLOG(HAL, Debug) << \"Camera ID: \" << id << \" removed successfully.\";\n+}\n+\n+CameraHalManager::cameraDeviceIter CameraHalManager::cameraIterFromId(unsigned int id)\n+{\n+\treturn std::find_if(cameras_.begin(), cameras_.end(),\n+\t\t\t [id](std::shared_ptr<CameraDevice> &camera) {\n+\t\t\t\treturn camera->id() == id;\n+\t\t\t });\n+}\n+\n+CameraHalManager::cameraDeviceIter CameraHalManager::cameraIterFromCamera(Camera *cam)\n+{\n+\treturn std::find_if(cameras_.begin(), cameras_.end(),\n+\t\t\t [cam](std::shared_ptr<CameraDevice> &camera) {\n+\t\t\t\treturn cam == camera->camera();\n+\t\t\t });\n+}\n+\n unsigned int CameraHalManager::numCameras() const\n {\n-\treturn cameraManager_->cameras().size();\n+\treturn internalCameras_;\n }\n \n int CameraHalManager::getCameraInfo(unsigned int id, struct camera_info *info)\n@@ -103,12 +204,15 @@ int CameraHalManager::getCameraInfo(unsigned int id, struct camera_info *info)\n \tif (!info)\n \t\treturn -EINVAL;\n \n-\tif (id >= numCameras()) {\n+\tMutexLocker locker(mutex_);\n+\n+\tauto iter = cameraIterFromId(id);\n+\tif (iter == cameras_.end()) {\n \t\tLOG(HAL, Error) << \"Invalid camera id '\" << id << \"'\";\n \t\treturn -EINVAL;\n \t}\n \n-\tCameraDevice *camera = cameras_[id].get();\n+\tCameraDevice *camera = iter->get();\n \n \tinfo->facing = camera->facing();\n \tinfo->orientation = camera->orientation();\n@@ -124,4 +228,30 @@ int CameraHalManager::getCameraInfo(unsigned int id, struct camera_info *info)\n void CameraHalManager::setCallbacks(const camera_module_callbacks_t *callbacks)\n {\n \tcallbacks_ = callbacks;\n+\n+\tMutexLocker locker(mutex_);\n+\n+\t/*\n+\t * Some external cameras may have been identified before the\n+\t * callbacks_ were enabled. Iterate any existing external\n+\t * cameras and mark them as CAMERA_DEVICE_STATUS_PRESENT\n+\t * explicitly.\n+\t *\n+\t * Internal cameras are already assumed to be present at module\n+\t * load time by the android framework.\n+\t */\n+\tfor (auto &cam : cameraManager_->cameras()) {\n+\t\tauto iter = camerasMap_.find(cam->id());\n+\t\tif (iter == camerasMap_.end())\n+\t\t\tcontinue;\n+\n+\t\tunsigned int id = iter->second;\n+\t\tconst ControlList &properties = cam->properties();\n+\t\tif (properties.contains(properties::Location) &&\n+\t\t properties.get(properties::Location) &\n+\t\t properties::CameraLocationExternal) {\n+\t\t\tcallbacks_->camera_device_status_change(callbacks_, id,\n+\t\t\t\t\t\t\t\tCAMERA_DEVICE_STATUS_PRESENT);\n+\t\t}\n+\t}\n }\ndiff --git a/src/android/camera_hal_manager.h b/src/android/camera_hal_manager.h\nindex 3e34d63..f8adade 100644\n--- a/src/android/camera_hal_manager.h\n+++ b/src/android/camera_hal_manager.h\n@@ -7,6 +7,8 @@\n #ifndef __ANDROID_CAMERA_MANAGER_H__\n #define __ANDROID_CAMERA_MANAGER_H__\n \n+#include <map>\n+#include <mutex>\n #include <stddef.h>\n #include <vector>\n \n@@ -18,12 +20,17 @@\n \n class CameraDevice;\n \n+using Mutex = std::mutex;\n+using MutexLocker = std::unique_lock<std::mutex>;\n+\n class CameraHalManager\n {\n public:\n \tCameraHalManager();\n \t~CameraHalManager();\n \n+\tusing cameraDeviceIter = std::vector<std::shared_ptr<CameraDevice>>::iterator;\n+\n \tint init();\n \n \tCameraDevice *open(unsigned int id, const hw_module_t *module);\n@@ -33,10 +40,21 @@ public:\n \tvoid setCallbacks(const camera_module_callbacks_t *callbacks);\n \n private:\n+\tvoid cameraAdded(std::shared_ptr<libcamera::Camera> cam);\n+\tvoid cameraRemoved(std::shared_ptr<libcamera::Camera> cam);\n+\n+\tcameraDeviceIter cameraIterFromId(unsigned int id);\n+\tcameraDeviceIter cameraIterFromCamera(libcamera::Camera *cam);\n+\n \tlibcamera::CameraManager *cameraManager_;\n \n \tconst camera_module_callbacks_t *callbacks_;\n \tstd::vector<std::shared_ptr<CameraDevice>> cameras_;\n+\tstd::map<std::string, unsigned int> camerasMap_;\n+\tMutex mutex_;\n+\n+\tunsigned int internalCameras_;\n+\tunsigned int externalCameras_;\n };\n \n #endif /* __ANDROID_CAMERA_MANAGER_H__ */\n", "prefixes": [ "libcamera-devel", "v3", "5/5" ] }