summaryrefslogtreecommitdiff
path: root/src/android/camera3_hal.cpp
blob: a5ad2374a9b65ab5e0aa2bbc42a843c703b77286 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
 * Copyright (C) 2019, Google Inc.
 *
 * Android Camera HALv3 module
 */

#include <hardware/camera_common.h>

#include <libcamera/base/log.h>

#include "camera_device.h"
#include "camera_hal_manager.h"

using namespace libcamera;

LOG_DEFINE_CATEGORY(HAL)

/*------------------------------------------------------------------------------
 * Android Camera HAL callbacks
 */

static int hal_get_number_of_cameras()
{
	return CameraHalManager::instance()->numCameras();
}

static int hal_get_camera_info(int id, struct camera_info *info)
{
	return CameraHalManager::instance()->getCameraInfo(id, info);
}

static int hal_set_callbacks(const camera_module_callbacks_t *callbacks)
{
	CameraHalManager::instance()->setCallbacks(callbacks);

	return 0;
}

static int hal_open_legacy([[maybe_unused]] const struct hw_module_t *module,
			   [[maybe_unused]] const char *id,
			   [[maybe_unused]] uint32_t halVersion,
			   [[maybe_unused]] struct hw_device_t **device)
{
	return -ENOSYS;
}

static int hal_set_torch_mode([[maybe_unused]] const char *camera_id,
			      [[maybe_unused]] bool enabled)
{
	return -ENOSYS;
}

/*
 * First entry point of the camera HAL module.
 *
 * Initialize the HAL but does not open any camera device yet (see hal_dev_open)
 */
static int hal_init()
{
	LOG(HAL, Info) << "Initialising Android camera HAL";

	CameraHalManager::instance()->init();

	return 0;
}

/*------------------------------------------------------------------------------
 * Android Camera Device
 */

static int hal_dev_open(const hw_module_t *module, const char *name,
			hw_device_t **device)
{
	LOG(HAL, Debug) << "Open camera " << name;

	int id = atoi(name);

	auto [camera, ret] = CameraHalManager::instance()->open(id, module);
	if (!camera) {
		LOG(HAL, Error)
			<< "Failed to open camera module '" << id << "'";
		return ret == -EBUSY ? -EUSERS : ret;
	}

	*device = &camera->camera3Device()->common;

	return 0;
}

static struct hw_module_methods_t hal_module_methods = {
	.open = hal_dev_open,
};

camera_module_t HAL_MODULE_INFO_SYM = {
	.common = {
		.tag = HARDWARE_MODULE_TAG,
		.module_api_version = CAMERA_MODULE_API_VERSION_2_4,
		.hal_api_version = HARDWARE_HAL_API_VERSION,
		.id = CAMERA_HARDWARE_MODULE_ID,
		.name = "libcamera camera HALv3 module",
		.author = "libcamera",
		.methods = &hal_module_methods,
		.dso = nullptr,
		.reserved = {},
	},

	.get_number_of_cameras = hal_get_number_of_cameras,
	.get_camera_info = hal_get_camera_info,
	.set_callbacks = hal_set_callbacks,
	.get_vendor_tag_ops = nullptr,
	.open_legacy = hal_open_legacy,
	.set_torch_mode = hal_set_torch_mode,
	.init = hal_init,
	.reserved = {},
};
> #include <libcamera/base/utils.h> #include <libcamera/camera.h> #include <libcamera/property_ids.h> #include "libcamera/internal/camera.h" #include "libcamera/internal/device_enumerator.h" #include "libcamera/internal/pipeline_handler.h" /** * \file libcamera/camera_manager.h * \brief The camera manager */ /** * \file libcamera/internal/camera_manager.h * \brief Internal camera manager support */ /** * \brief Top-level libcamera namespace */ namespace libcamera { LOG_DEFINE_CATEGORY(Camera) CameraManager::Private::Private() : initialized_(false) { } int CameraManager::Private::start() { int status; /* Start the thread and wait for initialization to complete. */ Thread::start(); { MutexLocker locker(mutex_); cv_.wait(locker, [&]() LIBCAMERA_TSA_REQUIRES(mutex_) { return initialized_; }); status = status_; } /* If a failure happened during initialization, stop the thread. */ if (status < 0) { exit(); wait(); return status; } return 0; } void CameraManager::Private::run() { LOG(Camera, Debug) << "Starting camera manager"; int ret = init(); mutex_.lock(); status_ = ret; initialized_ = true; mutex_.unlock(); cv_.notify_one(); if (ret < 0) return; /* Now start processing events and messages. */ exec(); cleanup(); } int CameraManager::Private::init() { enumerator_ = DeviceEnumerator::create(); if (!enumerator_ || enumerator_->enumerate()) return -ENODEV; createPipelineHandlers(); enumerator_->devicesAdded.connect(this, &Private::createPipelineHandlers); return 0; } void CameraManager::Private::createPipelineHandlers() { /* * \todo Try to read handlers and order from configuration * file and only fallback on environment variable or all handlers, if * there is no configuration file. */ const char *pipesList = utils::secure_getenv("LIBCAMERA_PIPELINES_MATCH_LIST"); if (pipesList) { /* * When a list of preferred pipelines is defined, iterate * through the ordered list to match the enumerated devices. */ for (const auto &pipeName : utils::split(pipesList, ",")) { const PipelineHandlerFactoryBase *factory; factory = PipelineHandlerFactoryBase::getFactoryByName(pipeName); if (!factory) continue; LOG(Camera, Debug) << "Found listed pipeline handler '" << pipeName << "'"; pipelineFactoryMatch(factory); } return; } const std::vector<PipelineHandlerFactoryBase *> &factories = PipelineHandlerFactoryBase::factories(); /* Match all the registered pipeline handlers. */ for (const PipelineHandlerFactoryBase *factory : factories) { LOG(Camera, Debug) << "Found registered pipeline handler '" << factory->name() << "'"; /* * Try each pipeline handler until it exhaust * all pipelines it can provide. */ pipelineFactoryMatch(factory); } } void CameraManager::Private::pipelineFactoryMatch(const PipelineHandlerFactoryBase *factory) { CameraManager *const o = LIBCAMERA_O_PTR(); /* Provide as many matching pipelines as possible. */ while (1) { std::shared_ptr<PipelineHandler> pipe = factory->create(o); if (!pipe->match(enumerator_.get())) break; LOG(Camera, Debug) << "Pipeline handler \"" << factory->name() << "\" matched"; } } void CameraManager::Private::cleanup() { enumerator_->devicesAdded.disconnect(this); /* * Release all references to cameras to ensure they all get destroyed * before the device enumerator deletes the media devices. Cameras are * destroyed via Object::deleteLater() API, hence we need to explicitly * process deletion requests from the thread's message queue as the event * loop is not in action here. */ { MutexLocker locker(mutex_); cameras_.clear(); } dispatchMessages(Message::Type::DeferredDelete); enumerator_.reset(nullptr); } /** * \brief Add a camera to the camera manager * \param[in] camera The camera to be added * * This function is called by pipeline handlers to register the cameras they * handle with the camera manager. Registered cameras are immediately made * available to the system. * * Device numbers from the SystemDevices property are used by the V4L2 * compatibility layer to map V4L2 device nodes to Camera instances. * * \context This function shall be called from the CameraManager thread. */ void CameraManager::Private::addCamera(std::shared_ptr<Camera> camera) { ASSERT(Thread::current() == this); MutexLocker locker(mutex_); for (const std::shared_ptr<Camera> &c : cameras_) { if (c->id() == camera->id()) { LOG(Camera, Fatal) << "Trying to register a camera with a duplicated ID '" << camera->id() << "'"; return; } } cameras_.push_back(std::move(camera)); unsigned int index = cameras_.size() - 1; /* Report the addition to the public signal */ CameraManager *const o = LIBCAMERA_O_PTR(); o->cameraAdded.emit(cameras_[index]); } /** * \brief Remove a camera from the camera manager * \param[in] camera The camera to be removed * * This function is called by pipeline handlers to unregister cameras from the * camera manager. Unregistered cameras won't be reported anymore by the * cameras() and get() calls, but references may still exist in applications. * * \context This function shall be called from the CameraManager thread. */ void CameraManager::Private::removeCamera(std::shared_ptr<Camera> camera) { ASSERT(Thread::current() == this); MutexLocker locker(mutex_); auto iter = std::find_if(cameras_.begin(), cameras_.end(), [camera](std::shared_ptr<Camera> &c) { return c.get() == camera.get(); }); if (iter == cameras_.end()) return; LOG(Camera, Debug) << "Unregistering camera '" << camera->id() << "'"; cameras_.erase(iter); /* Report the removal to the public signal */ CameraManager *const o = LIBCAMERA_O_PTR(); o->cameraRemoved.emit(camera); } /** * \class CameraManager * \brief Provide access and manage all cameras in the system * * The camera manager is the entry point to libcamera. It enumerates devices, * associates them with pipeline managers, and provides access to the cameras * in the system to applications. The manager owns all Camera objects and * handles hot-plugging and hot-unplugging to manage the lifetime of cameras. * * To interact with libcamera, an application starts by creating a camera * manager instance. Only a single instance of the camera manager may exist at * a time. Attempting to create a second instance without first deleting the * existing instance results in undefined behaviour. * * The manager is initially stopped, and shall be started with start(). This * will enumerate all the cameras present in the system, which can then be * listed with list() and retrieved with get(). * * Cameras are shared through std::shared_ptr<>, ensuring that a camera will * stay valid until the last reference is released without requiring any special * action from the application. Once the application has released all the * references it held to cameras, the camera manager can be stopped with * stop(). */ CameraManager *CameraManager::self_ = nullptr; CameraManager::CameraManager() : Extensible(std::make_unique<CameraManager::Private>()) { if (self_) LOG(Camera, Fatal) << "Multiple CameraManager objects are not allowed"; self_ = this; } /** * \brief Destroy the camera manager * * Destroying the camera manager stops it if it is currently running. */ CameraManager::~CameraManager() { stop(); self_ = nullptr; } /** * \brief Start the camera manager * * Start the camera manager and enumerate all devices in the system. Once * the start has been confirmed the user is free to list and otherwise * interact with cameras in the system until either the camera manager * is stopped or the camera is unplugged from the system. * * \return 0 on success or a negative error code otherwise */ int CameraManager::start() { LOG(Camera, Info) << "libcamera " << version_; int ret = _d()->start(); if (ret) LOG(Camera, Error) << "Failed to start camera manager: " << strerror(-ret); return ret; } /** * \brief Stop the camera manager * * Before stopping the camera manager the caller is responsible for making * sure all cameras provided by the manager are returned to the manager. * * After the manager has been stopped no resource provided by the camera * manager should be consider valid or functional even if they for one * reason or another have yet to be deleted. */ void CameraManager::stop() { Private *const d = _d(); d->exit(); d->wait(); } /** * \fn CameraManager::cameras() * \brief Retrieve all available cameras * * Before calling this function the caller is responsible for ensuring that * the camera manager is running. * * \context This function is \threadsafe. * * \return List of all available cameras */ std::vector<std::shared_ptr<Camera>> CameraManager::cameras() const { const Private *const d = _d(); MutexLocker locker(d->mutex_); return d->cameras_; } /** * \brief Get a camera based on ID * \param[in] id ID of camera to get * * Before calling this function the caller is responsible for ensuring that * the camera manager is running. * * \context This function is \threadsafe. * * \return Shared pointer to Camera object or nullptr if camera not found */ std::shared_ptr<Camera> CameraManager::get(const std::string &id) { Private *const d = _d(); MutexLocker locker(d->mutex_); for (std::shared_ptr<Camera> camera : d->cameras_) { if (camera->id() == id) return camera; } return nullptr; } /** * \var CameraManager::cameraAdded * \brief Notify of a new camera added to the system * * This signal is emitted when a new camera is detected and successfully handled * by the camera manager. The notification occurs alike for cameras detected * when the manager is started with start() or when new cameras are later * connected to the system. When the signal is emitted the new camera is already * available from the list of cameras(). * * The signal is emitted from the CameraManager thread. Applications shall * minimize the time spent in the signal handler and shall in particular not * perform any blocking operation. */ /** * \var CameraManager::cameraRemoved * \brief Notify of a new camera removed from the system * * This signal is emitted when a camera is removed from the system. When the * signal is emitted the camera is not available from the list of cameras() * anymore. * * The signal is emitted from the CameraManager thread. Applications shall * minimize the time spent in the signal handler and shall in particular not * perform any blocking operation. */ /** * \fn const std::string &CameraManager::version() * \brief Retrieve the libcamera version string * \context This function is \a threadsafe. * \return The libcamera version string */ } /* namespace libcamera */