From patchwork Sat Dec 22 23:00:30 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 77 Return-Path: Received: from bin-mail-out-05.binero.net (bin-mail-out-05.binero.net [195.74.38.228]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 29AC360B31 for ; Sun, 23 Dec 2018 00:02:17 +0100 (CET) X-Halon-ID: 90233b24-063d-11e9-9adf-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from wyvern.dyn.berto.se (unknown [217.31.177.236]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 90233b24-063d-11e9-9adf-005056917a89; Sun, 23 Dec 2018 00:01:50 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 23 Dec 2018 00:00:30 +0100 Message-Id: <20181222230041.29999-2-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> References: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 01/12] libcamera: Add Camera class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 22 Dec 2018 23:02:17 -0000 Provide a Camera class which represents our main interface to handling camera devices. This is a rework of Kieran's initial proposal and Laurent's documentation of the file changed to fit the device enumerators needs. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart --- include/libcamera/camera.h | 31 +++++++++++ include/libcamera/libcamera.h | 2 + include/libcamera/meson.build | 1 + src/libcamera/camera.cpp | 97 +++++++++++++++++++++++++++++++++++ src/libcamera/meson.build | 1 + 5 files changed, 132 insertions(+) create mode 100644 include/libcamera/camera.h create mode 100644 src/libcamera/camera.cpp diff --git a/include/libcamera/camera.h b/include/libcamera/camera.h new file mode 100644 index 0000000000000000..7622385cc94c11cd --- /dev/null +++ b/include/libcamera/camera.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2018, Google Inc. + * + * camera.h - Camera object interface + */ +#ifndef __LIBCAMERA_CAMERA_H__ +#define __LIBCAMERA_CAMERA_H__ + +#include + +namespace libcamera { + +class Camera +{ +public: + Camera(const std::string &name); + ~Camera(); + + const std::string &name() const; + void get(); + void put(); + +private: + int ref_; + std::string name_; +}; + +} + +#endif /* __LIBCAMERA_CAMERA_H__ */ diff --git a/include/libcamera/libcamera.h b/include/libcamera/libcamera.h index 790771b61e41e123..44c094d92feed5ba 100644 --- a/include/libcamera/libcamera.h +++ b/include/libcamera/libcamera.h @@ -7,6 +7,8 @@ #ifndef __LIBCAMERA_LIBCAMERA_H__ #define __LIBCAMERA_LIBCAMERA_H__ +#include + namespace libcamera { class libcamera diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build index 8c82675a25d29913..9b266ad926681db9 100644 --- a/include/libcamera/meson.build +++ b/include/libcamera/meson.build @@ -1,4 +1,5 @@ libcamera_api = files([ + 'camera.h', 'libcamera.h', ]) diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp new file mode 100644 index 0000000000000000..a85516876ce79ba4 --- /dev/null +++ b/src/libcamera/camera.cpp @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2018, Google Inc. + * + * camera.cpp - Camera device + */ + +#include + +#include "log.h" + +/** + * \file camera.h + * \brief Camera device handling + * + * At the core of libcamera is the camera device, combining one image source + * with processing hardware able to provide one or multiple image streams. The + * Camera class represents a camera device. + * + * A camera device contains a single image source, and separate camera device + * instances relate to different image sources. For instance, a phone containing + * front and back image sensors will be modelled with two camera devices, one + * for each sensor. When multiple streams can be produced from the same image + * source, all those streams are guaranteed to be part of the same camera + * device. + * + * While not sharing image sources, separate camera devices can share other + * system resources, such as an ISP. For this reason camera device instances may + * not be fully independent, in which case usage restrictions may apply. For + * instance, a phone with a front and a back camera device may not allow usage + * of the two devices simultaneously. + */ + +namespace libcamera { + +/** + * \class Camera + * \brief Camera device + * + * The Camera class models a camera capable of producing one or more image + * streams from a single image source. It provides the main interface to + * configuring and controlling the device, and capturing image streams. It is + * the central object exposed by libcamera. + */ + +/** + * \brief Construct a named camera device + * + * \param[in] name The name to set on the camera device + * + * The caller is responsible for guaranteeing unicity of the camera + * device name. + */ +Camera::Camera(const std::string &name) + : ref_(1), name_(name) +{ + LOG(Debug) << "Camera Constructed for " << name_; +} + +Camera::~Camera() +{ + if (ref_) + LOG(Error) << "Camera Destroyed while still in use!"; + else + LOG(Debug) << "Camera Destroyed"; +} + +/** + * \brief Retrieve the name of the camera + * + * \return Name of the camera device + */ +const std::string &Camera::name() const +{ + return name_; +} + +/** + * \brief Increase the use count of the camera + */ +void Camera::get() +{ + ref_++; +} + +/** + * \brief Decreases the use count of the camera. + * + * When the use count of the camera reaches zero the camera device is deleted. + */ +void Camera::put() +{ + if (--ref_ == 0) + delete this; +} + +} /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index f632eb5dd7791ad2..46591069aa5f8beb 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -1,4 +1,5 @@ libcamera_sources = files([ + 'camera.cpp', 'log.cpp', 'main.cpp', ]) From patchwork Sat Dec 22 23:00:31 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 78 Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BCF9B60B2D for ; Sun, 23 Dec 2018 00:02:18 +0100 (CET) X-Halon-ID: 913c5980-063d-11e9-9adf-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from wyvern.dyn.berto.se (unknown [217.31.177.236]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 913c5980-063d-11e9-9adf-005056917a89; Sun, 23 Dec 2018 00:01:52 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 23 Dec 2018 00:00:31 +0100 Message-Id: <20181222230041.29999-3-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> References: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 02/12] libcamera: add dependency on libudev X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 22 Dec 2018 23:02:19 -0000 The device enumeration will depend on libudev, add the dependency to the build system. This should be turned into a optional dependency once a device enumerator not using udev is supported. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart --- src/libcamera/meson.build | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 46591069aa5f8beb..52b556a8ed4050cb 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -16,7 +16,10 @@ includes = [ libcamera_internal_includes, ] +libudev = dependency('libudev') + libcamera = shared_library('camera', libcamera_sources, install : true, - include_directories : includes) + include_directories : includes, + dependencies : libudev) From patchwork Sat Dec 22 23:00:32 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 79 Return-Path: Received: from bin-mail-out-06.binero.net (bin-mail-out-06.binero.net [195.74.38.229]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 582E360B2D for ; Sun, 23 Dec 2018 00:02:21 +0100 (CET) X-Halon-ID: 92559c6b-063d-11e9-9adf-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from wyvern.dyn.berto.se (unknown [217.31.177.236]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 92559c6b-063d-11e9-9adf-005056917a89; Sun, 23 Dec 2018 00:01:54 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 23 Dec 2018 00:00:32 +0100 Message-Id: <20181222230041.29999-4-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> References: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 03/12] libcamera: deviceenumerator: add DeviceInfo class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 22 Dec 2018 23:02:21 -0000 Provide a DeviceInfo class which holds all information from the initial enumeration of a media device. Not all information available at a media device is stored, only the information needed for a pipeline handler to find a specific device. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart --- src/libcamera/deviceenumerator.cpp | 78 ++++++++++++++++++++++++ src/libcamera/include/deviceenumerator.h | 44 +++++++++++++ src/libcamera/meson.build | 2 + 3 files changed, 124 insertions(+) create mode 100644 src/libcamera/deviceenumerator.cpp create mode 100644 src/libcamera/include/deviceenumerator.h diff --git a/src/libcamera/deviceenumerator.cpp b/src/libcamera/deviceenumerator.cpp new file mode 100644 index 0000000000000000..7c44a65b45472ef3 --- /dev/null +++ b/src/libcamera/deviceenumerator.cpp @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2018, Google Inc. + * + * deviceenumerator.cpp - Enumeration and matching + */ + +#include "deviceenumerator.h" +#include "log.h" + +namespace libcamera { + +/* ----------------------------------------------------------------------------- + * DeviceInfo + */ + +DeviceInfo::DeviceInfo(const std::string &devnode, const struct media_device_info &info, + const std::map &entities) + : acquired_(false), devnode_(devnode), info_(info), entities_(entities) +{ + for (const auto &entity : entities_) + LOG(Info) << "Device: " << devnode_ << " Entity: '" << entity.first << "' -> " << entity.second; +} + +int DeviceInfo::acquire() +{ + if (acquired_) + return -EBUSY; + + acquired_ = true; + + return 0; +} + +void DeviceInfo::release() +{ + acquired_ = false; +} + +bool DeviceInfo::busy() const +{ + return acquired_; +} + +const std::string &DeviceInfo::devnode() const +{ + return devnode_; +} + +const struct media_device_info &DeviceInfo::info() const +{ + return info_; +} + +std::vector DeviceInfo::entities() const +{ + std::vector entities; + + for (const auto &entity : entities_) + entities.push_back(entity.first); + + return entities; +} + +bool DeviceInfo::lookup(const std::string &name, std::string &devnode) const +{ + auto it = entities_.find(name); + + if (it == entities_.end()) { + LOG(Error) << "Trying to lookup entity '" << name << "' which do not exist"; + return false; + } + + devnode = it->second; + return true; +} + +} /* namespace libcamera */ diff --git a/src/libcamera/include/deviceenumerator.h b/src/libcamera/include/deviceenumerator.h new file mode 100644 index 0000000000000000..0136ed6ea23bf65e --- /dev/null +++ b/src/libcamera/include/deviceenumerator.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2018, Google Inc. + * + * deviceenumerator.h - API to enumerate and find media devices + */ +#ifndef __LIBCAMERA_DEVICEENUMERATE_H__ +#define __LIBCAMERA_DEVICEENUMERATE_H__ + +#include +#include +#include + +#include + +namespace libcamera { + +class DeviceInfo +{ +public: + DeviceInfo(const std::string &devnode, const struct media_device_info &info, + const std::map &entities); + + int acquire(); + void release(); + bool busy() const; + + const std::string &devnode() const; + const struct media_device_info &info() const; + std::vector entities() const; + + bool lookup(const std::string &name, std::string &devnode) const; + +private: + bool acquired_; + + std::string devnode_; + struct media_device_info info_; + std::map entities_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_DEVICEENUMERATE_H__ */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 52b556a8ed4050cb..17cdf06dd2bedfb3 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -1,10 +1,12 @@ libcamera_sources = files([ 'camera.cpp', + 'deviceenumerator.cpp', 'log.cpp', 'main.cpp', ]) libcamera_headers = files([ + 'include/deviceenumerator.h', 'include/log.h', 'include/utils.h', ]) From patchwork Sat Dec 22 23:00:33 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 80 Return-Path: Received: from bin-mail-out-06.binero.net (bin-mail-out-06.binero.net [195.74.38.229]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D693960B31 for ; Sun, 23 Dec 2018 00:02:22 +0100 (CET) X-Halon-ID: 936ed3d0-063d-11e9-9adf-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from wyvern.dyn.berto.se (unknown [217.31.177.236]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 936ed3d0-063d-11e9-9adf-005056917a89; Sun, 23 Dec 2018 00:01:56 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 23 Dec 2018 00:00:33 +0100 Message-Id: <20181222230041.29999-5-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> References: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 04/12] libcamera: deviceenumerator: add DeviceMatch class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 22 Dec 2018 23:02:23 -0000 Provide a DeviceMatch class which represents all properties of a media device a pipeline hander can specify when searching for a device to use in its pipeline. Signed-off-by: Niklas Söderlund --- src/libcamera/deviceenumerator.cpp | 54 ++++++++++++++++++++++++ src/libcamera/include/deviceenumerator.h | 17 ++++++++ 2 files changed, 71 insertions(+) diff --git a/src/libcamera/deviceenumerator.cpp b/src/libcamera/deviceenumerator.cpp index 7c44a65b45472ef3..17b6874d229c791c 100644 --- a/src/libcamera/deviceenumerator.cpp +++ b/src/libcamera/deviceenumerator.cpp @@ -75,4 +75,58 @@ bool DeviceInfo::lookup(const std::string &name, std::string &devnode) const return true; } +/* ----------------------------------------------------------------------------- + * DeviceMatch + */ + +DeviceMatch::DeviceMatch(const std::string &driver) + : driver_(driver) +{ +} + +void DeviceMatch::add(const std::string &entity) +{ + entities_.push_back(std::string(entity)); +} + +bool DeviceMatch::match(const DeviceInfo *info) const +{ + std::vector entities; + + if (!matchInfo(info->info())) + return false; + + if (!matchEntities(info->entities())) + return false; + + return true; +} + +bool DeviceMatch::matchInfo(const struct media_device_info &info) const +{ + /* TODO: Add more optinal matching pairs from struct media_device_info */ + /* TODO: Allow for empty driver in DeviceMatch */ + return driver_ == info.driver; +} + +bool DeviceMatch::matchEntities(const std::vector &entities) const +{ + for (const std::string &name : entities_) { + bool found = false; + + for (const std::string &entity : entities) { + + if (name == entity) { + found = true; + break; + } + } + + if (!found) + return false; + } + + return true; +} + } /* namespace libcamera */ diff --git a/src/libcamera/include/deviceenumerator.h b/src/libcamera/include/deviceenumerator.h index 0136ed6ea23bf65e..fb412b8840cb2ffe 100644 --- a/src/libcamera/include/deviceenumerator.h +++ b/src/libcamera/include/deviceenumerator.h @@ -39,6 +39,23 @@ private: std::map entities_; }; +class DeviceMatch +{ +public: + DeviceMatch(const std::string &driver); + + void add(const std::string &entity); + + bool match(const DeviceInfo *info) const; + +private: + std::string driver_; + std::vector entities_; + + bool matchInfo(const struct media_device_info &info) const; + bool matchEntities(const std::vector &entities) const; +}; + } /* namespace libcamera */ #endif /* __LIBCAMERA_DEVICEENUMERATE_H__ */ From patchwork Sat Dec 22 23:00:34 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 81 Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5B05960B2D for ; Sun, 23 Dec 2018 00:02:24 +0100 (CET) X-Halon-ID: 946979a7-063d-11e9-9adf-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from wyvern.dyn.berto.se (unknown [217.31.177.236]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 946979a7-063d-11e9-9adf-005056917a89; Sun, 23 Dec 2018 00:01:57 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 23 Dec 2018 00:00:34 +0100 Message-Id: <20181222230041.29999-6-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> References: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 05/12] libcamera: deviceenumerator: add DeviceEnumerator class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 22 Dec 2018 23:02:24 -0000 Provide a DeviceEnumerator base class which enumerates all media devices in the system and information about them, resolving V4L2 data structures to paths and a method to search in all the enumerated information. Signed-off-by: Niklas Söderlund --- src/libcamera/deviceenumerator.cpp | 144 +++++++++++++++++++++++ src/libcamera/include/deviceenumerator.h | 22 ++++ 2 files changed, 166 insertions(+) diff --git a/src/libcamera/deviceenumerator.cpp b/src/libcamera/deviceenumerator.cpp index 17b6874d229c791c..b2f59017e94d14aa 100644 --- a/src/libcamera/deviceenumerator.cpp +++ b/src/libcamera/deviceenumerator.cpp @@ -5,6 +5,10 @@ * deviceenumerator.cpp - Enumeration and matching */ +#include +#include +#include + #include "deviceenumerator.h" #include "log.h" @@ -129,4 +133,144 @@ bool DeviceMatch::matchEntities(const std::vector &entities) const return true; } +/* ----------------------------------------------------------------------------- + * Enumerator Base + */ + +DeviceEnumerator::~DeviceEnumerator() +{ + for (DeviceInfo *dev : devices_) { + if (dev->busy()) + LOG(Error) << "Removing device info while still in use"; + + delete dev; + } +} + +int DeviceEnumerator::addDevice(const std::string &devnode) +{ + int fd, ret; + + struct media_device_info info = {}; + std::map entities; + + fd = open(devnode.c_str(), O_RDWR); + if (fd < 0) + return fd; + + ret = readInfo(fd, info); + if (ret) + goto out; + + ret = readTopology(fd, entities); + if (ret) + goto out; + + devices_.push_back(new DeviceInfo(devnode, info, entities)); +out: + close(fd); + + return ret; +} + +int DeviceEnumerator::readInfo(int fd, struct media_device_info &info) +{ + int ret; + + ret = ioctl(fd, MEDIA_IOC_DEVICE_INFO, &info); + if (ret < 0) + return -errno; + + return 0; +} + +int DeviceEnumerator::readTopology(int fd, std::map &entities) +{ + struct media_v2_topology topology; + struct media_v2_entity *ents = NULL; + struct media_v2_interface *ifaces = NULL; + struct media_v2_link *links = NULL; + int ret; + + while (true) { + topology = {}; + + ret = ioctl(fd, MEDIA_IOC_G_TOPOLOGY, &topology); + if (ret < 0) + return -errno; + + __u64 version = topology.topology_version; + + ents = new media_v2_entity[topology.num_entities](); + ifaces = new media_v2_interface[topology.num_interfaces](); + links = new media_v2_link[topology.num_links](); + topology.ptr_entities = (__u64)ents; + topology.ptr_interfaces = (__u64)ifaces; + topology.ptr_links = (__u64)links; + + ret = ioctl(fd, MEDIA_IOC_G_TOPOLOGY, &topology); + if (ret < 0) { + ret = -errno; + goto done; + } + + if (version == topology.topology_version) + break; + + delete[] links; + delete[] ifaces; + delete[] ents; + } + + for (unsigned int link_id = 0; link_id < topology.num_links; link_id++) { + unsigned int iface_id, ent_id; + std::string devnode; + + if ((links[link_id].flags & MEDIA_LNK_FL_LINK_TYPE) != MEDIA_LNK_FL_INTERFACE_LINK) + continue; + + for (iface_id = 0; iface_id < topology.num_interfaces; iface_id++) + if (links[link_id].source_id == ifaces[iface_id].id) + break; + + for (ent_id = 0; ent_id < topology.num_entities; ent_id++) + if (links[link_id].sink_id == ents[ent_id].id) + break; + + if (ent_id >= topology.num_entities || iface_id >= topology.num_interfaces) + continue; + + ret = lookupDevnode(devnode, + ifaces[iface_id].devnode.major, + ifaces[iface_id].devnode.minor); + if (ret) + break; + + entities[ents[ent_id].name] = devnode; + } +done: + delete[] links; + delete[] ifaces; + delete[] ents; + + return ret; +} + +DeviceInfo *DeviceEnumerator::search(DeviceMatch &dm) const +{ + DeviceInfo *info = NULL; + + for (DeviceInfo *dev : devices_) { + if (dev->busy()) + continue; + + if (dm.match(dev)) { + info = dev; + break; + } + } + + return info; +} + } /* namespace libcamera */ diff --git a/src/libcamera/include/deviceenumerator.h b/src/libcamera/include/deviceenumerator.h index fb412b8840cb2ffe..cbe17774edb7fcc5 100644 --- a/src/libcamera/include/deviceenumerator.h +++ b/src/libcamera/include/deviceenumerator.h @@ -56,6 +56,28 @@ private: bool matchEntities(const std::vector &entities) const; }; +class DeviceEnumerator +{ +public: + virtual ~DeviceEnumerator(); + + virtual int init() = 0; + virtual int enumerate() = 0; + + DeviceInfo *search(DeviceMatch &dm) const; + +protected: + int addDevice(const std::string &devnode); + +private: + std::vector devices_; + + int readInfo(int fd, struct media_device_info &info); + int readTopology(int fd, std::map &entities); + + virtual int lookupDevnode(std::string &devnode, int major, int minor) = 0; +}; + } /* namespace libcamera */ #endif /* __LIBCAMERA_DEVICEENUMERATE_H__ */ From patchwork Sat Dec 22 23:00:35 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 82 Return-Path: Received: from bin-mail-out-06.binero.net (bin-mail-out-06.binero.net [195.74.38.229]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 12ABD60B2C for ; Sun, 23 Dec 2018 00:02:26 +0100 (CET) X-Halon-ID: 95a1b78c-063d-11e9-9adf-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from wyvern.dyn.berto.se (unknown [217.31.177.236]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 95a1b78c-063d-11e9-9adf-005056917a89; Sun, 23 Dec 2018 00:01:59 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 23 Dec 2018 00:00:35 +0100 Message-Id: <20181222230041.29999-7-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> References: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 06/12] libcamera: deviceenumerator: add DeviceEnumeratorUdev class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 22 Dec 2018 23:02:26 -0000 Provide a DeviceEnumeratorUdev class which is a specialization of DeviceEnumerator which uses udev to enumerate information in the system. Signed-off-by: Niklas Söderlund --- src/libcamera/deviceenumerator.cpp | 100 +++++++++++++++++++++++ src/libcamera/include/deviceenumerator.h | 15 ++++ 2 files changed, 115 insertions(+) diff --git a/src/libcamera/deviceenumerator.cpp b/src/libcamera/deviceenumerator.cpp index b2f59017e94d14aa..f4c40bf0376ab453 100644 --- a/src/libcamera/deviceenumerator.cpp +++ b/src/libcamera/deviceenumerator.cpp @@ -6,6 +6,7 @@ */ #include +#include #include #include @@ -273,4 +274,103 @@ DeviceInfo *DeviceEnumerator::search(DeviceMatch &dm) const return info; } +/* ----------------------------------------------------------------------------- + * Enumerator Udev + */ + +DeviceEnumeratorUdev::DeviceEnumeratorUdev() + : udev_(NULL) +{ +} + +DeviceEnumeratorUdev::~DeviceEnumeratorUdev() +{ + if (udev_) + udev_unref(udev_); +} + +int DeviceEnumeratorUdev::init() +{ + if (udev_) + return -EBUSY; + + udev_ = udev_new(); + if (!udev_) + return -ENODEV; + + return 0; +} + +int DeviceEnumeratorUdev::enumerate() +{ + struct udev_enumerate *udev_enum = NULL; + struct udev_list_entry *ents, *ent; + int ret; + + udev_enum = udev_enumerate_new(udev_); + if (udev_enum == NULL) + return -ENOMEM; + + ret = udev_enumerate_add_match_subsystem(udev_enum, "media"); + if (ret < 0) + goto done; + + ret = udev_enumerate_scan_devices(udev_enum); + if (ret < 0) + goto done; + + ents = udev_enumerate_get_list_entry(udev_enum); + if (ents == NULL) + goto done; + + udev_list_entry_foreach(ent, ents) { + struct udev_device *dev; + const char *devnode; + const char *syspath = udev_list_entry_get_name(ent); + + dev = udev_device_new_from_syspath(udev_, syspath); + if (dev == NULL) { + LOG(Error) << "Failed to device for '" << syspath << "', skipping"; + continue; + } + + devnode = udev_device_get_devnode(dev); + if (devnode == NULL) { + udev_device_unref(dev); + ret = -ENODEV; + goto done; + } + + addDevice(devnode); + + udev_device_unref(dev); + } +done: + udev_enumerate_unref(udev_enum); + return ret >= 0 ? 0 : ret; +} + +int DeviceEnumeratorUdev::lookupDevnode(std::string &devnode, int major, int minor) +{ + struct udev_device *device; + const char *name; + dev_t devnum; + int ret = 0; + + devnum = makedev(major, minor); + device = udev_device_new_from_devnum(udev_, 'c', devnum); + if (!device) + return -ENODEV; + + name = udev_device_get_devnode(device); + if (name) + devnode = name; + else + ret = -ENODEV; + + udev_device_unref(device); + + return ret; +} + } /* namespace libcamera */ diff --git a/src/libcamera/include/deviceenumerator.h b/src/libcamera/include/deviceenumerator.h index cbe17774edb7fcc5..2c7ff3f336ba127d 100644 --- a/src/libcamera/include/deviceenumerator.h +++ b/src/libcamera/include/deviceenumerator.h @@ -78,6 +78,21 @@ private: virtual int lookupDevnode(std::string &devnode, int major, int minor) = 0; }; +class DeviceEnumeratorUdev: public DeviceEnumerator +{ +public: + DeviceEnumeratorUdev(); + ~DeviceEnumeratorUdev(); + + int init() final; + int enumerate() final; + +private: + struct udev *udev_; + + int lookupDevnode(std::string &devnode, int major, int minor) final; +}; + } /* namespace libcamera */ #endif /* __LIBCAMERA_DEVICEENUMERATE_H__ */ From patchwork Sat Dec 22 23:00:36 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 83 Return-Path: Received: from bin-mail-out-05.binero.net (bin-mail-out-05.binero.net [195.74.38.228]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 19A0A60B31 for ; Sun, 23 Dec 2018 00:02:28 +0100 (CET) X-Halon-ID: 96ba8d9d-063d-11e9-9adf-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from wyvern.dyn.berto.se (unknown [217.31.177.236]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 96ba8d9d-063d-11e9-9adf-005056917a89; Sun, 23 Dec 2018 00:02:01 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 23 Dec 2018 00:00:36 +0100 Message-Id: <20181222230041.29999-8-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> References: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 07/12] libcamera: deviceenumerator: add factory for DeviceEnumerators X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 22 Dec 2018 23:02:28 -0000 Provide a factory for DeviceEnumerator objects. Depending on which libraries are available there will be different ways to enumerate information in the system. This factory hides this from the rest of the library. Currently udev enumeration is the only supported implementation, a sysfs implementation is another method that surely will be added in the future. Signed-off-by: Niklas Söderlund Reviewed-by: Laurent Pinchart --- src/libcamera/deviceenumerator.cpp | 17 +++++++++++++++++ src/libcamera/include/deviceenumerator.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/src/libcamera/deviceenumerator.cpp b/src/libcamera/deviceenumerator.cpp index f4c40bf0376ab453..6d675fc78af8e586 100644 --- a/src/libcamera/deviceenumerator.cpp +++ b/src/libcamera/deviceenumerator.cpp @@ -138,6 +138,23 @@ bool DeviceMatch::matchEntities(const std::vector &entities) const * Enumerator Base */ +DeviceEnumerator *DeviceEnumerator::create() +{ + DeviceEnumerator *enumerator; + + /* TODO: add compile time checks to only try udev enumerator if libudev is available */ + enumerator = new DeviceEnumeratorUdev(); + if (!enumerator->init()) + return enumerator; + + /* NOTE: Either udev is not available or initialization of it + * failed, use/fallback on sysfs enumerator */ + + /* TODO: add a sysfs based enumerator */ + + return NULL; +} + DeviceEnumerator::~DeviceEnumerator() { for (DeviceInfo *dev : devices_) { diff --git a/src/libcamera/include/deviceenumerator.h b/src/libcamera/include/deviceenumerator.h index 2c7ff3f336ba127d..6aa6e59d4a8a9729 100644 --- a/src/libcamera/include/deviceenumerator.h +++ b/src/libcamera/include/deviceenumerator.h @@ -59,6 +59,8 @@ private: class DeviceEnumerator { public: + static DeviceEnumerator *create(); + virtual ~DeviceEnumerator(); virtual int init() = 0; From patchwork Sat Dec 22 23:00:37 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 84 Return-Path: Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8817E60B34 for ; Sun, 23 Dec 2018 00:02:30 +0100 (CET) X-Halon-ID: 97d4075f-063d-11e9-9adf-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from wyvern.dyn.berto.se (unknown [217.31.177.236]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 97d4075f-063d-11e9-9adf-005056917a89; Sun, 23 Dec 2018 00:02:03 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 23 Dec 2018 00:00:37 +0100 Message-Id: <20181222230041.29999-9-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> References: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 08/12] libcamera: deviceenumerator: add documentation X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 22 Dec 2018 23:02:30 -0000 Document the intended use-case of the different elements of the device enumerator. Signed-off-by: Niklas Söderlund --- src/libcamera/deviceenumerator.cpp | 249 +++++++++++++++++++++++++++-- 1 file changed, 239 insertions(+), 10 deletions(-) diff --git a/src/libcamera/deviceenumerator.cpp b/src/libcamera/deviceenumerator.cpp index 6d675fc78af8e586..fc43ecc7e2d07e05 100644 --- a/src/libcamera/deviceenumerator.cpp +++ b/src/libcamera/deviceenumerator.cpp @@ -13,12 +13,55 @@ #include "deviceenumerator.h" #include "log.h" +/** + * \file deviceenumerator.h + * \brief Enumerating and matching of media devices + * + * The purpose of device enumeration and matching is to find media + * devices in the system and map one or more media devices to a pipeline + * handler. During enumeration information about each media device is + * gathered, transformed and stored. + * + * The core of the enumeration is DeviceEnumerator which is responsible + * for all interactions with the operating system and the entry point + * for other parts of libcamera. + * + * The DeviceEnumerator can enumerate all or specific media devices in + * the system. When a new media device is added the enumerator gathers + * information about it and stores it in a DeviceInfo object. + * + * The last functionality provided is the ability to search among the + * enumerate media devices for one matching information known to the + * searcher. This is done by populating and passing a DeviceMatch object + * to the DeviceEnumerator. + * + * \todo Add sysfs based device enumerator + * \todo Add support for hot-plug and hot-unplug. + */ + namespace libcamera { -/* ----------------------------------------------------------------------------- - * DeviceInfo +/** + * \class DeviceInfo + * \brief Container of information for enumerated device + * + * The DeviceInfo class holds information about a media device. It provides + * methods to retrieve the information stored and to lookup entity names + * to device node paths. Furthermore it provides a scheme where a device + * can be acquired and released to indicate if the device is in use. + * + * \todo Look into the possibility to replace this with a more complete MediaDevice model. */ +/** + * \brief Construct a container of device information + * + * \param[in] devnode The path to the device node of the media device + * \param[in] info Information retrieved from MEDIA_IOC_DEVICE_INFO IOCTL + * \param[in] entities A map of media graph 'Entity name' -> 'devnode path' + * + * The caller is responsible to provide all information for the device. + */ DeviceInfo::DeviceInfo(const std::string &devnode, const struct media_device_info &info, const std::map &entities) : acquired_(false), devnode_(devnode), info_(info), entities_(entities) @@ -27,6 +70,15 @@ DeviceInfo::DeviceInfo(const std::string &devnode, const struct media_device_inf LOG(Info) << "Device: " << devnode_ << " Entity: '" << entity.first << "' -> " << entity.second; } +/** + * \brief Claim a device for exclusive use + * + * Once a device is successfully acquired the caller is responsible to + * release it once it is done wit it. + * + * \retval 0 Device claimed + * \retval -EBUSY Device already claimed by someone else + */ int DeviceInfo::acquire() { if (acquired_) @@ -37,26 +89,53 @@ int DeviceInfo::acquire() return 0; } +/** + * \brief Release a device from exclusive use + */ void DeviceInfo::release() { acquired_ = false; } +/** + * \brief Check if a device is in use + * + * \retval true Device is in use + * \retval false Device is free + */ bool DeviceInfo::busy() const { return acquired_; } +/** + * \brief Retrieve the devnode to the media device + * + * \return Path to the media device (example /dev/media0) + */ const std::string &DeviceInfo::devnode() const { return devnode_; } +/** + * \brief Retrieve the media device v4l2 information + * + * \return v4l2 specific information structure + */ const struct media_device_info &DeviceInfo::info() const { return info_; } +/** + * \brief List all entities of the device + * + * List all media entities names from the media graph which are known + * and to which this instance can lookup the device node path. + * + * \return List of strings + */ std::vector DeviceInfo::entities() const { std::vector entities; @@ -67,6 +146,19 @@ std::vector DeviceInfo::entities() const return entities; } +/** + * \brief Lookup a media entity name and retrieve its device node path + * + * \param[in] name Entity name to lookup + * \param[out] devnode Path to \a name devnode if lookup is successful + * + * The caller is responsible to check the return code of the function + * to determine if the entity name could be looked up. + * + * \retval true Successful - \a devnode contains valid data + * \retval false Fail - \a devnode contains invalid data + * + */ bool DeviceInfo::lookup(const std::string &name, std::string &devnode) const { auto it = entities_.find(name); @@ -80,20 +172,49 @@ bool DeviceInfo::lookup(const std::string &name, std::string &devnode) const return true; } -/* ----------------------------------------------------------------------------- - * DeviceMatch +/** + * \class DeviceMatch + * \brief Description of a media device search pattern + * + * The DeviceMatch class describes a media device using properties from + * the v4l2 struct media_device_info, entity names in the media graph or + * other properties which can be used to identify a media device. + * + * The description of a media device can then be passed to an enumerator + * to try and find a matching media device. */ +/** + * \brief Construct a media device search pattern + * + * \param[in] driver The Linux device driver name who created the media device + */ DeviceMatch::DeviceMatch(const std::string &driver) : driver_(driver) { } +/** + * \brief Add a media entity name to the search pattern + * + * \param[in] entity The name of the entity in the media graph + */ void DeviceMatch::add(const std::string &entity) { entities_.push_back(std::string(entity)); } +/** + * \brief Compare a search pattern with a media device + * + * \param[in] info Information about a enumerated media device + * + * Matching is performed on the Linux device driver name and entity names + * from the media graph. + * + * \retval true The device described in \a info matches search pattern + * \retval false The device described in \a info do not match search pattern + */ bool DeviceMatch::match(const DeviceInfo *info) const { std::vector entities; @@ -107,13 +228,32 @@ bool DeviceMatch::match(const DeviceInfo *info) const return true; } +/** + * \brief Compare a v4l2 struct media_device_info to search pattern + * + * \param[in] info Information about a enumerated media device + * + * Not all parameters of struct media_device_info is compared. + * + * \todo Allow for empty driver_ search pattern as a no-op + * \todo Add more optional matching pairs from struct media_device_info + * + * \retval true The device described in \a info matches search pattern + * \retval false The device described in \a info do not match search pattern + */ bool DeviceMatch::matchInfo(const struct media_device_info &info) const { - /* TODO: Add more optinal matching pairs from struct media_device_info */ - /* TODO: Allow for empty driver in DeviceMatch */ return driver_ == info.driver; } +/** + * \brief Compare media entities of media device with search pattern + * + * \param[in] info Information about a enumerated media device + * + * \retval true The device described in \a info matches search pattern + * \retval false The device described in \a info do not match search pattern + */ bool DeviceMatch::matchEntities(const std::vector &entities) const { for (const std::string &name : entities_) { @@ -134,10 +274,30 @@ bool DeviceMatch::matchEntities(const std::vector &entities) const return true; } -/* ----------------------------------------------------------------------------- - * Enumerator Base +/** + * \class DeviceEnumerator + * \brief Enumerate, interrogate, store and search media device information + * + * The DeviceEnumerator class is responsible for all interactions with + * the operation system when searching and interrogating media devices. + * + * It is possible to automatically search and add all media devices in + * the system or specify which media devices should be interrogated + * in order for a specialized application to open as few resources + * as possible to get hold of a specific camera. + * + * Once one or many media devices have been enumerated it is possible + * to search among them to try and find a matching device using a + * DeviceMatch object. + * */ +/** + * \brief Create a new device enumerator matching the systems capabilities + * + * Create a enumerator based on resource available to the system. Not all + * different enumerator types are guaranteed to support all features. + */ DeviceEnumerator *DeviceEnumerator::create() { DeviceEnumerator *enumerator; @@ -165,6 +325,15 @@ DeviceEnumerator::~DeviceEnumerator() } } +/** + * \brief Add a media device to the enumerator + * + * \param[in] devnode path to the media device to add + * + * Opens the media device and quires its topology and other information. + * + * \return 0 on success none zero otherwise + */ int DeviceEnumerator::addDevice(const std::string &devnode) { int fd, ret; @@ -191,6 +360,16 @@ out: return ret; } +/** + * \brief Fetch the MEDIA_IOC_DEVICE_INFO from media device + * + * \param[in] fd File pointer to media device + * \param[out] info Information retrieved from MEDIA_IOC_DEVICE_INFO IOCTL + * + * Opens the media device and quires its information. + * + * \return 0 on success none zero otherwise + */ int DeviceEnumerator::readInfo(int fd, struct media_device_info &info) { int ret; @@ -202,6 +381,18 @@ int DeviceEnumerator::readInfo(int fd, struct media_device_info &info) return 0; } +/** + * \brief Fetch the topology from media device + * + * \param[in] fd File pointer to media device + * \param[out] entities Map of entity names to device node paths + * + * The media graph is retrieved using MEDIA_IOC_G_TOPOLOGY and the + * result is transformed to a map where the entity name is the key + * and the filesystem path for that entity device node is the value. + * + * \return 0 on success none zero otherwise + */ int DeviceEnumerator::readTopology(int fd, std::map &entities) { struct media_v2_topology topology; @@ -274,6 +465,18 @@ done: return ret; } +/** + * \brief Search available media devices for a pattern match + * + * \param[in] dm search pattern + * + * Search the enumerated media devices who are not already in use + * for a match described in \a dm. If a match is found and the caller + * intends to use it the caller is responsible to mark the DeviceInfo + * object as in use and to release it when it's done with it. + * + * \return pointer to the matching DeviceInfo, NULL if no match is found + */ DeviceInfo *DeviceEnumerator::search(DeviceMatch &dm) const { DeviceInfo *info = NULL; @@ -291,8 +494,11 @@ DeviceInfo *DeviceEnumerator::search(DeviceMatch &dm) const return info; } -/* ----------------------------------------------------------------------------- - * Enumerator Udev +/** + * \class DeviceEnumeratorUdev + * \brief Udev implementation of device enumeration + * + * Implementation of system enumeration functions using libudev. */ DeviceEnumeratorUdev::DeviceEnumeratorUdev() @@ -306,6 +512,13 @@ DeviceEnumeratorUdev::~DeviceEnumeratorUdev() udev_unref(udev_); } +/** + * \brief Initialize the enumerator + * + * \retval 0 Initialized + * \retval -EBUSY Busy (already initialized) + * \retval -ENODEV Failed to talk to udev + */ int DeviceEnumeratorUdev::init() { if (udev_) @@ -318,6 +531,14 @@ int DeviceEnumeratorUdev::init() return 0; } +/** + * \brief Enumerate all media devices using udev + * + * Find, enumerate and add all media devices in the system to the + * enumerator. + * + * \return 0 on success none zero otherwise + */ int DeviceEnumeratorUdev::enumerate() { struct udev_enumerate *udev_enum = NULL; @@ -367,6 +588,14 @@ done: return ret >= 0 ? 0 : ret; } +/** + * \brief Lookup device node from device number using udev + * + * Translate a device number (major, minor) to a device node path. + * + * \return 0 on success none zero otherwise + * + */ int DeviceEnumeratorUdev::lookupDevnode(std::string &devnode, int major, int minor) { struct udev_device *device; From patchwork Sat Dec 22 23:00:38 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 85 Return-Path: Received: from bin-mail-out-05.binero.net (bin-mail-out-05.binero.net [195.74.38.228]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 1EF1C60B34 for ; Sun, 23 Dec 2018 00:02:33 +0100 (CET) X-Halon-ID: 996a0c8f-063d-11e9-9adf-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from wyvern.dyn.berto.se (unknown [217.31.177.236]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 996a0c8f-063d-11e9-9adf-005056917a89; Sun, 23 Dec 2018 00:02:06 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 23 Dec 2018 00:00:38 +0100 Message-Id: <20181222230041.29999-10-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> References: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 09/12] libcamera: pipelinehandler: add PipelineHandler class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 22 Dec 2018 23:02:33 -0000 Provide a PipelineHandler which represents a handler for one or more media devices and provider of one or more cameras. Signed-off-by: Niklas Söderlund --- src/libcamera/include/pipelinehandler.h | 71 ++++++++++++++ src/libcamera/meson.build | 2 + src/libcamera/pipelinehandler.cpp | 122 ++++++++++++++++++++++++ 3 files changed, 195 insertions(+) create mode 100644 src/libcamera/include/pipelinehandler.h create mode 100644 src/libcamera/pipelinehandler.cpp diff --git a/src/libcamera/include/pipelinehandler.h b/src/libcamera/include/pipelinehandler.h new file mode 100644 index 0000000000000000..0e2f497a4fda3caa --- /dev/null +++ b/src/libcamera/include/pipelinehandler.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2018, Google Inc. + * + * pipelinehandler.h - Pipeline handler infrastructure + */ +#ifndef __LIBCAMERA_PIPELINEHANDLER_H__ +#define __LIBCAMERA_PIPELINEHANDLER_H__ + +#include +#include +#include + +#include + +namespace libcamera { + +class DeviceEnumerator; +class PipelineHandlerFactory; + +class PipelineHandler +{ +public: + virtual ~PipelineHandler() { }; + + virtual bool match(DeviceEnumerator *enumerator) = 0; + + virtual unsigned int count() = 0; + virtual Camera *camera(unsigned int id) = 0; + + static void registerType(const std::string &name, PipelineHandlerFactory *factory); + static PipelineHandler *create(const std::string &name, DeviceEnumerator *enumerator); + static void handlers(std::vector &handlers); + +private: + static std::map ®istry(); +}; + +class PipelineHandlerFactory +{ +public: + + virtual ~PipelineHandlerFactory() { }; + + virtual PipelineHandler *create() = 0; +}; + +/** + * \brief Register a pipeline hander with the global list + * + * \param[in] handler Class name of PipelineHandler subclass to register + * + * Register a specifc pipline handler with the global list and make it + * avaiable to try and match devices for libcamera. + */ +#define REGISTER_PIPELINE(handler) \ + class handler##Factory : public PipelineHandlerFactory { \ + public: \ + handler##Factory() \ + { \ + PipelineHandler::registerType(#handler, this); \ + } \ + virtual PipelineHandler *create() { \ + return new handler(); \ + } \ + }; \ + static handler##Factory global_##handler##Factory; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_PIPELINEHANDLER_H__ */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 17cdf06dd2bedfb3..0776643d3064129d 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -3,11 +3,13 @@ libcamera_sources = files([ 'deviceenumerator.cpp', 'log.cpp', 'main.cpp', + 'pipelinehandler.cpp', ]) libcamera_headers = files([ 'include/deviceenumerator.h', 'include/log.h', + 'include/pipelinehandler.h', 'include/utils.h', ]) diff --git a/src/libcamera/pipelinehandler.cpp b/src/libcamera/pipelinehandler.cpp new file mode 100644 index 0000000000000000..3c47f1ceb72eb6f6 --- /dev/null +++ b/src/libcamera/pipelinehandler.cpp @@ -0,0 +1,122 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2018, Google Inc. + * + * pipelinehandler.cpp - Pipeline handler infrastructure + */ + +#include "deviceenumerator.h" +#include "log.h" +#include "pipelinehandler.h" + +/** + * \file pipelinehandler.h + * \brief Create pipelines and cameras from one or more media device + * + * Each pipeline supported by libcamera needs to be backed by a pipeline + * handler implementation which describes the one or many media devices + * needed for a pipeline to function properly. + * + * The pipeline handler is responsible to find all media devices it requires + * to operate and once it retrieves them create all the camera devices + * it is able to support with the that set of devices. + * + * To make it a bit less bit complicated to write pipe line handlers a + * important macro REGISTER_PIPELINE() is provided which allows a pipeline + * hander implementation to register itself with the library with ease. + * + * \todo Figure out how and if the PipelineHandler should be involved in + * controlling cameras with resource dependencies and if the handler + * should provide helpers for cameras to control media graph links. + */ + +namespace libcamera { + + +/** + * \class PipelineHandler + * \brief Find a set of media devices and provide cameras + * + * The responsibility of a PipelineHandler is to describe all media + * devices it would need in order to provide cameras to the system. + */ + +/** + * \brief Add a pipeline hander to the global list + * + * \param[in] name Name of the pipeline handler to add + * \param[in] factory Factory to use to construct the pipeline + * + * The caller is responsible to guarantee the uniqueness of the pipeline name. + */ +void PipelineHandler::registerType(const std::string &name, PipelineHandlerFactory *factory) +{ + std::map &factories = registry(); + + if (factories.count(name)) { + LOG(Error) << "Registering '" << name << "' pipeline twice"; + return; + } + + factories[name] = factory; +} + +/** + * \brief Create a new pipeline hander and try to match it + * + * \param[in] name Name of the pipeline handler to try + * \param[in] enumerator Numerator to to search for a match for the handler + * + * Search \a enumerator for a match for a pipeline handler named \a name. + * + * \return Pipeline handler if a match was found else NULL + */ +PipelineHandler *PipelineHandler::create(const std::string &name, DeviceEnumerator *enumerator) +{ + std::map &factories = registry(); + + if (!factories.count(name)) { + LOG(Error) << "Trying to create non-existing pipeline handler " << name; + return NULL; + } + + PipelineHandler *pipe; + + pipe = factories[name]->create(); + + if (pipe->match(enumerator)) + return pipe; + + delete pipe; + return NULL; +} + +/** + * \brief List all names of handlers from the global list + * + * \param[out] handlers Names of all handlers registered with the global list + */ +void PipelineHandler::handlers(std::vector &handlers) +{ + std::map &factories = registry(); + + for (auto const &handler : factories) + handlers.push_back(handler.first); +} + +/** + * \brief Static global list of pipeline handlers + * + * It might seem odd to hide the static map inside a function. + * This is needed to make sure the list is created before anyone + * tries to access it and creating problems at link time. + * + * \return Global list of pipeline handlers + */ +std::map &PipelineHandler::registry() +{ + static std::map factories; + return factories; +} + +} /* namespace libcamera */ From patchwork Sat Dec 22 23:00:39 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 86 Return-Path: Received: from bin-mail-out-06.binero.net (bin-mail-out-06.binero.net [195.74.38.229]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 5231060B2E for ; Sun, 23 Dec 2018 00:02:35 +0100 (CET) X-Halon-ID: 9ae16192-063d-11e9-9adf-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from wyvern.dyn.berto.se (unknown [217.31.177.236]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 9ae16192-063d-11e9-9adf-005056917a89; Sun, 23 Dec 2018 00:02:08 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 23 Dec 2018 00:00:39 +0100 Message-Id: <20181222230041.29999-11-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> References: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 10/12] libcamera: cameramanager: add CameraManager class X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 22 Dec 2018 23:02:35 -0000 Provide a CameraManager class which will handle listing, instancing, destruction and lifetime management of cameras. Signed-off-by: Niklas Söderlund --- include/libcamera/cameramanager.h | 38 +++++++ include/libcamera/libcamera.h | 1 + include/libcamera/meson.build | 1 + src/libcamera/cameramanager.cpp | 173 ++++++++++++++++++++++++++++++ src/libcamera/meson.build | 1 + 5 files changed, 214 insertions(+) create mode 100644 include/libcamera/cameramanager.h create mode 100644 src/libcamera/cameramanager.cpp diff --git a/include/libcamera/cameramanager.h b/include/libcamera/cameramanager.h new file mode 100644 index 0000000000000000..be078a75f9e5aefc --- /dev/null +++ b/include/libcamera/cameramanager.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2018, Google Inc. + * + * cameramanager.h - Camera management + */ +#ifndef __LIBCAMERA_CAMERAMANAGER_H__ +#define __LIBCAMERA_CAMERAMANAGER_H__ + +#include +#include + +namespace libcamera { + +class Camera; +class DeviceEnumerator; +class PipelineHandler; + +class CameraManager +{ +public: + CameraManager(); + + bool start(); + void stop(); + + std::vector list() const; + Camera *get(const std::string &name); + void put(Camera *camera); + +private: + DeviceEnumerator *enumerator_; + std::vector pipes_; +}; + +} /* namespace libcamera */ + +#endif /* __LIBCAMERA_CAMERAMANAGER_H__ */ diff --git a/include/libcamera/libcamera.h b/include/libcamera/libcamera.h index 44c094d92feed5ba..286b3d4d28083b01 100644 --- a/include/libcamera/libcamera.h +++ b/include/libcamera/libcamera.h @@ -8,6 +8,7 @@ #define __LIBCAMERA_LIBCAMERA_H__ #include +#include namespace libcamera { diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build index 9b266ad926681db9..b7ba1f124aada003 100644 --- a/include/libcamera/meson.build +++ b/include/libcamera/meson.build @@ -1,5 +1,6 @@ libcamera_api = files([ 'camera.h', + 'cameramanager.h', 'libcamera.h', ]) diff --git a/src/libcamera/cameramanager.cpp b/src/libcamera/cameramanager.cpp new file mode 100644 index 0000000000000000..53209e32d88e3ed3 --- /dev/null +++ b/src/libcamera/cameramanager.cpp @@ -0,0 +1,173 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2018, Google Inc. + * + * cameramanager.h - Camera management + */ + +#include + +#include "deviceenumerator.h" +#include "pipelinehandler.h" + +/** + * \file cameramanager.h + * \brief Manage all cameras handled by libcamera + * + * The responsibility of the camera manager is to control the lifetime + * management of objects provided by libcamera. + * + * When a user wish to interact with libcamera it creates and starts a + * CameraManager object. Once confirmed the camera manager is running + * the application can list all cameras detected by the library, get + * one or more of the cameras and interact with them. + * + * When the user is done with the camera it should be returned to the + * camera manager. Once all cameras are returned to the camera manager + * the user is free to stop the manager. + * + * \todo Add ability to add and remove media devices based on + * hot-(un)plug events coming from the device enumerator. + * + * \todo Add interface to register a notification callback to the user + * to be able to inform it new cameras have been hot-plugged or + * cameras have been removed due to hot-unplug. + */ + +namespace libcamera { + +CameraManager::CameraManager() + : enumerator_(NULL) +{ +} + +/** + * \brief Start the camera manager + * + * Start the camera manager and enumerate all devices in the system. Once + * the stat have 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 true on successful start false otherwise + */ +bool CameraManager::start() +{ + std::vector handlers; + + if (enumerator_) + return false; + + enumerator_ = DeviceEnumerator::create(); + + if (enumerator_->enumerate()) + return false; + + /* TODO: Try to read handlers and order from configuration + * file and only fallback on all handlers if there is no + * configuration file. + */ + PipelineHandler::handlers(handlers); + + for (std::string const &handler : handlers) { + PipelineHandler *pipe; + + /* Try each pipeline handler until it exhaust + * all pipelines it can provide. */ + do { + pipe = PipelineHandler::create(handler, enumerator_); + if (pipe) + pipes_.push_back(pipe); + } while (pipe); + } + + /* TODO: register hot-plug callback here */ + + return true; +} + +/** + * \brief Stop the camera manager + * + * Before stopping the camera manger the caller is responsible for making + * sure all cameras provided by the manager are returned to the manager. + * + * After the manager have been stopped no resource provided my 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() +{ + /* TODO: unregister hot-plug callback here */ + + for (PipelineHandler *pipe : pipes_) + delete pipe; + + if (enumerator_) + delete enumerator_; + + enumerator_ = NULL; +} + +/** + * \brief List all detected cameras + * + * Before calling this function the caller is responsible to make sure + * the camera manger is running. + * + * \return List of names for all detected cameras + */ +std::vector CameraManager::list() const +{ + std::vector list; + + for (PipelineHandler *pipe : pipes_) { + for (unsigned int i = 0; i < pipe->count(); i++) { + Camera *cam = pipe->camera(i); + list.push_back(cam->name()); + } + } + + return list; +} + +/** + * \brief Get a camera based on name + * + * \param[in] name Name of camera to get + * + * Before calling this function the caller is responsible to make sure + * the camera manger is running. A camera fetched this way should be + * returned to the camera manger once the caller is done with it. + * + * \return Pointer to Camera object or NULL if camera not found + */ +Camera *CameraManager::get(const std::string &name) +{ + for (PipelineHandler *pipe : pipes_) { + for (unsigned int i = 0; i < pipe->count(); i++) { + Camera *cam = pipe->camera(i); + if (cam->name() == name) { + cam->get(); + return cam; + } + } + } + + return NULL; +} + +/** + * \brief Return camera to the camera manager + * + * \param[in] camera Camera to return to the manager + * + * After the camera have been returned to the camera manager the caller + * should not use the pointer to the camera object it has returned. + */ +void CameraManager::put(Camera *camera) +{ + camera->put(); +} + +} /* namespace libcamera */ diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 0776643d3064129d..8457e57939b862ed 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -1,5 +1,6 @@ libcamera_sources = files([ 'camera.cpp', + 'cameramanager.cpp', 'deviceenumerator.cpp', 'log.cpp', 'main.cpp', From patchwork Sat Dec 22 23:00:40 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 87 Return-Path: Received: from bin-mail-out-06.binero.net (bin-mail-out-06.binero.net [195.74.38.229]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id D975160B33 for ; Sun, 23 Dec 2018 00:02:36 +0100 (CET) X-Halon-ID: 9c38e1f1-063d-11e9-9adf-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from wyvern.dyn.berto.se (unknown [217.31.177.236]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 9c38e1f1-063d-11e9-9adf-005056917a89; Sun, 23 Dec 2018 00:02:10 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 23 Dec 2018 00:00:40 +0100 Message-Id: <20181222230041.29999-12-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> References: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 11/12] libcamera: pipe-vimc: add pipeline handler for vimc X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 22 Dec 2018 23:02:37 -0000 Provide a pipeline handler for the virtual vimc driver. Signed-off-by: Niklas Söderlund --- src/libcamera/meson.build | 1 + src/libcamera/pipe-vimc.cpp | 92 +++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 src/libcamera/pipe-vimc.cpp diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build index 8457e57939b862ed..088c76f72d331784 100644 --- a/src/libcamera/meson.build +++ b/src/libcamera/meson.build @@ -4,6 +4,7 @@ libcamera_sources = files([ 'deviceenumerator.cpp', 'log.cpp', 'main.cpp', + 'pipe-vimc.cpp', 'pipelinehandler.cpp', ]) diff --git a/src/libcamera/pipe-vimc.cpp b/src/libcamera/pipe-vimc.cpp new file mode 100644 index 0000000000000000..14bb96faece908de --- /dev/null +++ b/src/libcamera/pipe-vimc.cpp @@ -0,0 +1,92 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2018, Google Inc. + * + * pipe-vimc.cpp - Pipeline handler for the vimc device + */ + +#include + +#include "deviceenumerator.h" +#include "pipelinehandler.h" + +namespace libcamera { + +class PipeHandlerVimc : public PipelineHandler +{ +public: + PipeHandlerVimc(); + ~PipeHandlerVimc(); + + bool match(DeviceEnumerator *enumerator); + + unsigned int count(); + Camera *camera(unsigned int id); +private: + DeviceInfo *info_; + Camera *camera_; +}; + +PipeHandlerVimc::PipeHandlerVimc() + : info_(NULL), camera_(NULL) +{ +} + +PipeHandlerVimc::~PipeHandlerVimc() +{ + if (camera_) + camera_->put(); + + if (info_) + info_->release(); +} + +unsigned int PipeHandlerVimc::count() +{ + return 1; +} + +Camera *PipeHandlerVimc::camera(unsigned int id) +{ + if (id != 0) + return NULL; + + return camera_; +} + +bool PipeHandlerVimc::match(DeviceEnumerator *enumerator) +{ + DeviceMatch dm("vimc"); + + dm.add("Raw Capture 0"); + dm.add("Raw Capture 1"); + dm.add("RGB/YUV Capture"); + dm.add("Sensor A"); + dm.add("Sensor B"); + dm.add("Debayer A"); + dm.add("Debayer B"); + dm.add("RGB/YUV Input"); + dm.add("Scaler"); + + info_ = enumerator->search(dm); + + if (info_) { + info_->acquire(); + + /* NOTE: A more complete Camera implementation could + * be passed the DeviceInfo(s) it controls here or + * a reference to the PipelineHandler. Which method + * that is chosen will depend on how the Camera + * object is modeled. + */ + camera_ = new Camera("Dummy VIMC Camera"); + + return true; + } + + return info_ ? true : false; +} + +REGISTER_PIPELINE(PipeHandlerVimc); + +} /* namespace libcamera */ From patchwork Sat Dec 22 23:00:41 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Niklas_S=C3=B6derlund?= X-Patchwork-Id: 88 Return-Path: Received: from bin-mail-out-06.binero.net (bin-mail-out-06.binero.net [195.74.38.229]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 0F94060B0C for ; Sun, 23 Dec 2018 00:02:39 +0100 (CET) X-Halon-ID: 9d335f09-063d-11e9-9adf-005056917a89 Authorized-sender: niklas@soderlund.pp.se Received: from wyvern.dyn.berto.se (unknown [217.31.177.236]) by bin-vsp-out-01.atm.binero.net (Halon) with ESMTPA id 9d335f09-063d-11e9-9adf-005056917a89; Sun, 23 Dec 2018 00:02:12 +0100 (CET) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Sun, 23 Dec 2018 00:00:41 +0100 Message-Id: <20181222230041.29999-13-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> References: <20181222230041.29999-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH 12/12] tests: add test to list all cameras in the system X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 22 Dec 2018 23:02:39 -0000 Add simple test which lists all cameras detected in the system. The test fails if no camera can be found. Signed-off-by: Niklas Söderlund --- test/list.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ test/meson.build | 5 +++++ 2 files changed, 59 insertions(+) create mode 100644 test/list.cpp diff --git a/test/list.cpp b/test/list.cpp new file mode 100644 index 0000000000000000..6483ffb4f13a8cb6 --- /dev/null +++ b/test/list.cpp @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2018, Google Inc. + * + * list.cpp - camera list tests + */ + +#include + +#include + +#include "test.h" + +using namespace std; +using namespace libcamera; + +class ListTest : public Test +{ +protected: + int init() + { + cm = new CameraManager(); + if (!cm) + return -ENOMEM; + + cm->start(); + + return 0; + } + + int run() + { + unsigned int count = 0; + + for (auto name : cm->list()) { + cout << "- " << name << endl; + count++; + } + + return count ? 0 : -ENODEV; + } + + void cleanup() + { + cm->stop(); + + delete cm; + } + +private: + CameraManager *cm; +}; + +TEST_REGISTER(ListTest) diff --git a/test/meson.build b/test/meson.build index da0aea9678d127ce..a74629f89197ecea 100644 --- a/test/meson.build +++ b/test/meson.build @@ -8,4 +8,9 @@ test_init = executable('test_init', 'init.cpp', link_with : libcamera, include_directories : libcamera_includes) +list = executable('list', 'list.cpp', + link_with : [libcamera, libtest], + include_directories : libcamera_includes) + test('Initialisation test', test_init) +test('List Camera API tests', list)