diff options
Diffstat (limited to 'src/android/camera_hal_manager.cpp')
-rw-r--r-- | src/android/camera_hal_manager.cpp | 264 |
1 files changed, 220 insertions, 44 deletions
diff --git a/src/android/camera_hal_manager.cpp b/src/android/camera_hal_manager.cpp index 5bd3bdba..7500c749 100644 --- a/src/android/camera_hal_manager.cpp +++ b/src/android/camera_hal_manager.cpp @@ -2,20 +2,21 @@ /* * Copyright (C) 2019, Google Inc. * - * camera_hal_manager.cpp - libcamera Android Camera Manager + * libcamera Android Camera Manager */ #include "camera_hal_manager.h" -#include <libcamera/camera.h> +#include <libcamera/base/log.h> -#include "log.h" +#include <libcamera/camera.h> +#include <libcamera/property_ids.h> #include "camera_device.h" using namespace libcamera; -LOG_DECLARE_CATEGORY(HAL); +LOG_DECLARE_CATEGORY(HAL) /* * \class CameraHalManager @@ -28,71 +29,224 @@ LOG_DECLARE_CATEGORY(HAL); */ CameraHalManager::CameraHalManager() - : cameraManager_(nullptr) + : cameraManager_(nullptr), callbacks_(nullptr), numInternalCameras_(0), + nextExternalCameraId_(firstExternalCameraId_) { } -CameraHalManager::~CameraHalManager() -{ - cameras_.clear(); +/* CameraManager calls stop() in the destructor. */ +CameraHalManager::~CameraHalManager() = default; - if (cameraManager_) { - cameraManager_->stop(); - delete cameraManager_; - cameraManager_ = nullptr; - } +/* static */ +CameraHalManager *CameraHalManager::instance() +{ + static CameraHalManager *cameraHalManager = new CameraHalManager; + return cameraHalManager; } int CameraHalManager::init() { - cameraManager_ = new CameraManager(); + cameraManager_ = std::make_unique<CameraManager>(); + + /* + * If the configuration file is not available the HAL only supports + * external cameras. If it exists but it's not valid then error out. + */ + if (halConfig_.exists() && !halConfig_.isValid()) { + LOG(HAL, Error) << "HAL configuration file is not valid"; + return -EINVAL; + } + + /* Support camera hotplug. */ + cameraManager_->cameraAdded.connect(this, &CameraHalManager::cameraAdded); + cameraManager_->cameraRemoved.connect(this, &CameraHalManager::cameraRemoved); int ret = cameraManager_->start(); if (ret) { LOG(HAL, Error) << "Failed to start camera manager: " << strerror(-ret); - delete cameraManager_; - cameraManager_ = nullptr; + cameraManager_.reset(); return ret; } + return 0; +} + +std::tuple<CameraDevice *, int> +CameraHalManager::open(unsigned int id, const hw_module_t *hardwareModule) +{ + MutexLocker locker(mutex_); + + if (!callbacks_) { + LOG(HAL, Error) << "Can't open camera before callbacks are set"; + return { nullptr, -ENODEV }; + } + + CameraDevice *camera = cameraDeviceFromHalId(id); + if (!camera) { + LOG(HAL, Error) << "Invalid camera id '" << id << "'"; + return { nullptr, -ENODEV }; + } + + int ret = camera->open(hardwareModule); + if (ret) + return { nullptr, ret }; + + LOG(HAL, Info) << "Open camera '" << id << "'"; + + return { camera, 0 }; +} + +void CameraHalManager::cameraAdded(std::shared_ptr<Camera> cam) +{ + unsigned int id; + bool isCameraExternal = false; + bool isCameraNew = false; + + MutexLocker locker(mutex_); + /* - * For each Camera registered in the system, a CameraDevice - * gets created here to wraps a libcamera Camera instance. + * Each camera is assigned a unique integer ID when it is seen for the + * first time. If the camera has been seen before, the previous ID is + * re-used. * - * \todo Support camera hotplug. + * IDs starts from '0' for internal cameras and '1000' for external + * cameras. */ - unsigned int index = 0; - for (auto &cam : cameraManager_->cameras()) { - CameraDevice *camera = new CameraDevice(index, cam); - cameras_.emplace_back(camera); + auto iter = cameraIdsMap_.find(cam->id()); + if (iter != cameraIdsMap_.end()) { + id = iter->second; + if (id >= firstExternalCameraId_) + isCameraExternal = true; + } else { + isCameraNew = true; - ++index; + /* + * Now check if this is an external camera and assign + * its id accordingly. + */ + if (cameraLocation(cam.get()) == properties::CameraLocationExternal) { + isCameraExternal = true; + id = nextExternalCameraId_; + } else { + id = numInternalCameras_; + } } - return 0; + /* + * The configuration file must be valid, and contain a corresponding + * entry for internal cameras. External cameras can be initialized + * without configuration file. + */ + if (!isCameraExternal && !halConfig_.exists()) { + LOG(HAL, Error) + << "HAL configuration file is mandatory for internal cameras." + << " Camera " << cam->id() << " failed to load"; + return; + } + + const CameraConfigData *cameraConfigData = halConfig_.cameraConfigData(cam->id()); + + /* + * Some cameras whose location is reported by libcamera as external may + * actually be internal to the device. This is common with UVC cameras + * that are integrated in a laptop. In that case the real location + * should be specified in the configuration file. + * + * If the camera location is external and a configuration entry exists + * for it, override its location. + */ + if (isCameraNew && isCameraExternal) { + if (cameraConfigData && cameraConfigData->facing != -1) { + isCameraExternal = false; + id = numInternalCameras_; + } + } + + if (!isCameraExternal && !cameraConfigData) { + LOG(HAL, Error) + << "HAL configuration entry for internal camera " + << cam->id() << " is missing"; + return; + } + + /* Create a CameraDevice instance to wrap the libcamera Camera. */ + std::unique_ptr<CameraDevice> camera = CameraDevice::create(id, cam); + + int ret = camera->initialize(cameraConfigData); + if (ret) { + LOG(HAL, Error) << "Failed to initialize camera: " << cam->id(); + return; + } + + if (isCameraNew) { + cameraIdsMap_.emplace(cam->id(), id); + + if (isCameraExternal) + nextExternalCameraId_++; + else + numInternalCameras_++; + } + + cameras_.emplace_back(std::move(camera)); + + if (callbacks_) + callbacks_->camera_device_status_change(callbacks_, id, + CAMERA_DEVICE_STATUS_PRESENT); + + LOG(HAL, Debug) << "Camera ID: " << id << " added successfully."; } -CameraDevice *CameraHalManager::open(unsigned int id, - const hw_module_t *hardwareModule) +void CameraHalManager::cameraRemoved(std::shared_ptr<Camera> cam) { - if (id >= numCameras()) { - LOG(HAL, Error) << "Invalid camera id '" << id << "'"; - return nullptr; - } + MutexLocker locker(mutex_); - CameraDevice *camera = cameras_[id].get(); - if (camera->open(hardwareModule)) - return nullptr; + auto iter = std::find_if(cameras_.begin(), cameras_.end(), + [&cam](const std::unique_ptr<CameraDevice> &camera) { + return cam == camera->camera(); + }); + if (iter == cameras_.end()) + return; - LOG(HAL, Info) << "Open camera '" << id << "'"; + /* + * CAMERA_DEVICE_STATUS_NOT_PRESENT should be set for external cameras + * only. + */ + unsigned int id = (*iter)->id(); + if (id >= firstExternalCameraId_) + callbacks_->camera_device_status_change(callbacks_, id, + CAMERA_DEVICE_STATUS_NOT_PRESENT); + + /* + * \todo Check if the camera is already open and running. + * Inform the framework about its absence before deleting its + * reference here. + */ + cameras_.erase(iter); + + LOG(HAL, Debug) << "Camera ID: " << id << " removed successfully."; +} + +int32_t CameraHalManager::cameraLocation(const Camera *cam) +{ + return cam->properties().get(properties::Location).value_or(-1); +} - return camera; +CameraDevice *CameraHalManager::cameraDeviceFromHalId(unsigned int id) +{ + auto iter = std::find_if(cameras_.begin(), cameras_.end(), + [id](const std::unique_ptr<CameraDevice> &camera) { + return camera->id() == id; + }); + if (iter == cameras_.end()) + return nullptr; + + return iter->get(); } unsigned int CameraHalManager::numCameras() const { - return cameraManager_->cameras().size(); + return numInternalCameras_; } int CameraHalManager::getCameraInfo(unsigned int id, struct camera_info *info) @@ -100,17 +254,17 @@ int CameraHalManager::getCameraInfo(unsigned int id, struct camera_info *info) if (!info) return -EINVAL; - if (id >= numCameras()) { + MutexLocker locker(mutex_); + + CameraDevice *camera = cameraDeviceFromHalId(id); + if (!camera) { LOG(HAL, Error) << "Invalid camera id '" << id << "'"; return -EINVAL; } - CameraDevice *camera = cameras_[id].get(); - - /* \todo Get these info dynamically inspecting the camera module. */ - info->facing = id ? CAMERA_FACING_FRONT : CAMERA_FACING_BACK; - info->orientation = 0; - info->device_version = 0; + info->facing = camera->facing(); + info->orientation = camera->orientation(); + info->device_version = CAMERA_DEVICE_API_VERSION_3_3; info->resource_cost = 0; info->static_camera_characteristics = camera->getStaticMetadata(); info->conflicting_devices = nullptr; @@ -118,3 +272,25 @@ int CameraHalManager::getCameraInfo(unsigned int id, struct camera_info *info) return 0; } + +void CameraHalManager::setCallbacks(const camera_module_callbacks_t *callbacks) +{ + callbacks_ = callbacks; + + MutexLocker locker(mutex_); + + /* + * Some external cameras may have been identified before the callbacks_ + * were set. Iterate all existing external cameras and mark them as + * CAMERA_DEVICE_STATUS_PRESENT explicitly. + * + * Internal cameras are already assumed to be present at module load + * time by the Android framework. + */ + for (const std::unique_ptr<CameraDevice> &camera : cameras_) { + unsigned int id = camera->id(); + if (id >= firstExternalCameraId_) + callbacks_->camera_device_status_change(callbacks_, id, + CAMERA_DEVICE_STATUS_PRESENT); + } +} |