From patchwork Mon Aug 3 21:17:25 2020 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: 9155 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id F0C74BD87A for ; Mon, 3 Aug 2020 21:18:01 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id E049D6199D; Mon, 3 Aug 2020 23:18:00 +0200 (CEST) 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 9CC99605A9 for ; Mon, 3 Aug 2020 23:17:59 +0200 (CEST) X-Halon-ID: 9c7cf789-d5ce-11ea-86ee-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (p54ac52a8.dip0.t-ipconnect.de [84.172.82.168]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 9c7cf789-d5ce-11ea-86ee-0050569116f7; Mon, 03 Aug 2020 23:16:35 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 3 Aug 2020 23:17:25 +0200 Message-Id: <20200803211733.1037019-2-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200803211733.1037019-1-niklas.soderlund@ragnatech.se> References: <20200803211733.1037019-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v6 1/9] libcamera: device_enumerator: Add method to lookup sysfs path X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add an implementation to lookup a device nodes sysfs interface path based on the assumption that device name under /dev matches the one under /sysfs. Subclasses of the DeviceEnumerator may override this to create more clever methods to lookup the path. Signed-off-by: Niklas Söderlund --- include/libcamera/internal/device_enumerator.h | 2 ++ src/libcamera/device_enumerator.cpp | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/include/libcamera/internal/device_enumerator.h b/include/libcamera/internal/device_enumerator.h index a9850400229d2b53..11961f4f9304f6d7 100644 --- a/include/libcamera/internal/device_enumerator.h +++ b/include/libcamera/internal/device_enumerator.h @@ -45,6 +45,8 @@ public: std::shared_ptr search(const DeviceMatch &dm); + virtual std::string lookupSysfsPath(const std::string &deviceNode); + Signal<> devicesAdded; protected: diff --git a/src/libcamera/device_enumerator.cpp b/src/libcamera/device_enumerator.cpp index 647974b17341f44b..ef2451ac29159bf0 100644 --- a/src/libcamera/device_enumerator.cpp +++ b/src/libcamera/device_enumerator.cpp @@ -318,4 +318,18 @@ std::shared_ptr DeviceEnumerator::search(const DeviceMatch &dm) return nullptr; } +/** + * \brief Lookup a nodes sysfs path + * \param[in] deviceNode device node to lookup + * + * Lookup \a deviceNode sysfs interface. + * + * \return Path in sysfs + */ +std::string DeviceEnumerator::lookupSysfsPath(const std::string &deviceNode) +{ + std::string dev = basename(deviceNode.c_str()); + return "/sys/class/video4linux/" + dev; +} + } /* namespace libcamera */ From patchwork Mon Aug 3 21:17:26 2020 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: 9156 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 5BC47BD87A for ; Mon, 3 Aug 2020 21:18:04 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 10E6A61AC7; Mon, 3 Aug 2020 23:18:04 +0200 (CEST) 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 5E8BA60398 for ; Mon, 3 Aug 2020 23:18:00 +0200 (CEST) X-Halon-ID: 9cd2dc61-d5ce-11ea-86ee-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (p54ac52a8.dip0.t-ipconnect.de [84.172.82.168]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 9cd2dc61-d5ce-11ea-86ee-0050569116f7; Mon, 03 Aug 2020 23:16:36 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 3 Aug 2020 23:17:26 +0200 Message-Id: <20200803211733.1037019-3-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200803211733.1037019-1-niklas.soderlund@ragnatech.se> References: <20200803211733.1037019-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v6 2/9] libcamera: device_enumerator_udev: Add specialization for sysfs path X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" As udev may rename the V4L2 devices in /dev add a specialization that asks udev for the sysfs path instead of using the default method that makes the assumption that V4L2 devices are never renamed. Suggested-by: Laurent Pinchart Signed-off-by: Niklas Söderlund --- .../internal/device_enumerator_udev.h | 2 ++ src/libcamera/device_enumerator_udev.cpp | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/include/libcamera/internal/device_enumerator_udev.h b/include/libcamera/internal/device_enumerator_udev.h index 6f45be0c1c423d02..595b16acb89d98bb 100644 --- a/include/libcamera/internal/device_enumerator_udev.h +++ b/include/libcamera/internal/device_enumerator_udev.h @@ -35,6 +35,8 @@ public: int init(); int enumerate(); + std::string lookupSysfsPath(const std::string &deviceNode); + private: using DependencyMap = std::map>; diff --git a/src/libcamera/device_enumerator_udev.cpp b/src/libcamera/device_enumerator_udev.cpp index 96689daa5dd113dc..2e43b84f62e0333d 100644 --- a/src/libcamera/device_enumerator_udev.cpp +++ b/src/libcamera/device_enumerator_udev.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -193,6 +194,29 @@ done: return 0; } +std::string DeviceEnumeratorUdev::lookupSysfsPath(const std::string &deviceNode) +{ + struct stat st; + int ret = stat(deviceNode.c_str(), &st); + if (ret < 0) { + LOG(DeviceEnumerator, Error) + << "Unable to stat '" << deviceNode << "'"; + return {}; + } + + struct udev_device *dev = udev_device_new_from_devnum(udev_, 'c', + st.st_rdev); + if (!dev) { + LOG(DeviceEnumerator, Error) + << "Unable to make device from devnum " << st.st_rdev; + return {}; + } + + std::string path{ udev_device_get_syspath(dev) }; + udev_device_unref(dev); + return path; +} + int DeviceEnumeratorUdev::populateMediaDevice(MediaDevice *media, DependencyMap *deps) { std::set children; From patchwork Mon Aug 3 21:17:27 2020 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: 9157 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id CC200BD87A for ; Mon, 3 Aug 2020 21:18:04 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A4BE861A12; Mon, 3 Aug 2020 23:18:04 +0200 (CEST) Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 15B146092F for ; Mon, 3 Aug 2020 23:18:01 +0200 (CEST) X-Halon-ID: 9d5ac67f-d5ce-11ea-86ee-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (p54ac52a8.dip0.t-ipconnect.de [84.172.82.168]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 9d5ac67f-d5ce-11ea-86ee-0050569116f7; Mon, 03 Aug 2020 23:16:37 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 3 Aug 2020 23:17:27 +0200 Message-Id: <20200803211733.1037019-4-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200803211733.1037019-1-niklas.soderlund@ragnatech.se> References: <20200803211733.1037019-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v6 3/9] libcamera: v4l2_device: Add method to lookup device path X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Add a method to lookup a V4L2 devices path in sysfs. Signed-off-by: Niklas Söderlund --- * Changes since v5 - Expand documentation - Use DeviceEnumerator interface to lookup device path - Include stdlib.h - Use realpath(..., nullptr); ...; free(); * Changes since v3 - s/the device path/the device path in sysfs/ --- include/libcamera/internal/v4l2_device.h | 1 + src/libcamera/v4l2_device.cpp | 27 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/include/libcamera/internal/v4l2_device.h b/include/libcamera/internal/v4l2_device.h index bf643f2ec966bb33..3b605aab343b3b94 100644 --- a/include/libcamera/internal/v4l2_device.h +++ b/include/libcamera/internal/v4l2_device.h @@ -30,6 +30,7 @@ public: int setControls(ControlList *ctrls); const std::string &deviceNode() const { return deviceNode_; } + std::string devicePath() const; protected: V4L2Device(const std::string &deviceNode); diff --git a/src/libcamera/v4l2_device.cpp b/src/libcamera/v4l2_device.cpp index 56ea1ddda2c1425f..ef601d8e7e04b32a 100644 --- a/src/libcamera/v4l2_device.cpp +++ b/src/libcamera/v4l2_device.cpp @@ -9,11 +9,14 @@ #include #include +#include +#include #include #include #include #include +#include "libcamera/internal/device_enumerator.h" #include "libcamera/internal/log.h" #include "libcamera/internal/utils.h" #include "libcamera/internal/v4l2_controls.h" @@ -350,6 +353,30 @@ int V4L2Device::setControls(ControlList *ctrls) return ret; } +/** + * \brief Retrieve the device path in sysfs + * + * This function returns the sysfs path to the physical device backing the V4L2 + * device. The path is guaranteed to be an absolute path, without any symbolic + * link. + * + * \return The device path in sysfs + */ +std::string V4L2Device::devicePath() const +{ + std::unique_ptr de = DeviceEnumerator::create(); + std::string devicePath = de->lookupSysfsPath(deviceNode_) + "/device"; + + char *realPath = realpath(devicePath.c_str(), nullptr); + if (!realPath) + LOG(V4L2, Fatal) << "Can not resolve path for " << devicePath; + + std::string path{ realPath }; + free(realPath); + + return path; +} + /** * \brief Perform an IOCTL system call on the device node * \param[in] request The IOCTL request code From patchwork Mon Aug 3 21:17:28 2020 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: 9158 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 26877BD87B for ; Mon, 3 Aug 2020 21:18:05 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id D2E7D61B02; Mon, 3 Aug 2020 23:18:04 +0200 (CEST) Received: from vsp-unauthed02.binero.net (vsp-unauthed02.binero.net [195.74.38.227]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id B7F54605A9 for ; Mon, 3 Aug 2020 23:18:01 +0200 (CEST) X-Halon-ID: 9db76d77-d5ce-11ea-86ee-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (p54ac52a8.dip0.t-ipconnect.de [84.172.82.168]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 9db76d77-d5ce-11ea-86ee-0050569116f7; Mon, 03 Aug 2020 23:16:37 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 3 Aug 2020 23:17:28 +0200 Message-Id: <20200803211733.1037019-5-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200803211733.1037019-1-niklas.soderlund@ragnatech.se> References: <20200803211733.1037019-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v6 4/9] libcamera: utils: Add method to lookup firmware ID in sysfs X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" A devices firmware description is recorded differently in sysfs depending on if the devices uses OF or ACPI. Add a helper to abstract this, allowing users to not care which of the two are used. For OF-based systems the ID is the full path of the device in the device tree description. For ACPI-based systems the ID is the ACPI firmware nodes path. Both ID sources are guaranteed to be unique and persistent as long as the firmware of the system is not changed. Signed-off-by: Niklas Söderlund --- include/libcamera/internal/utils.h | 2 + src/libcamera/utils.cpp | 61 ++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/include/libcamera/internal/utils.h b/include/libcamera/internal/utils.h index 45cd6f120c51586b..69977340e2593db6 100644 --- a/include/libcamera/internal/utils.h +++ b/include/libcamera/internal/utils.h @@ -200,6 +200,8 @@ details::StringSplitter split(const std::string &str, const std::string &delim); std::string libcameraBuildPath(); std::string libcameraSourcePath(); +int tryLookupFirmwareID(const std::string &devPath, std::string *id); + constexpr unsigned int alignDown(unsigned int value, unsigned int alignment) { return value / alignment * alignment; diff --git a/src/libcamera/utils.cpp b/src/libcamera/utils.cpp index 615df46ac142a2a9..07ebce61f230e5f0 100644 --- a/src/libcamera/utils.cpp +++ b/src/libcamera/utils.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -444,6 +445,66 @@ std::string libcameraSourcePath() return path + "/"; } +/** + * \brief Try to read a device firmware ID from sysfs + * \param[in] devPath Path in sysfs to search + * \param[out] id Location to store ID if found + * + * The ID recorded in the devices firmware description is recorded differently + * in sysfs depending on if the devices uses OF or ACPI. This helper abstracts + * this away, allowing callers to not care which of the two are used. + * + * For OF-based systems the ID is the full path of the device in the device tree + * description. For ACPI-based systems the ID is the ACPI firmware nodes path. + * Both ID sources are guaranteed to be unique and persistent as long as the + * firmware of the system is not changed. + * + * \return 0 on success or a negative error code otherwise + * \retval -ENOMEM \a id is nullptr + * \retval -EINVAL Error when looking up firmware ID + * \retval -ENODEV No firmware ID aviable for device + */ +int tryLookupFirmwareID(const std::string &devPath, std::string *id) +{ + struct stat statbuf; + std::string path; + + if (!id) + return -EINVAL; + + /* Try to lookup ID as if the system where OF-based. */ + path = devPath + "/of_node"; + if (stat(path.c_str(), &statbuf) == 0) { + char *ofPath = realpath(path.c_str(), nullptr); + if (!ofPath) + return -EINVAL; + + *id = ofPath; + free(ofPath); + + static const std::string dropStr = "/sys/firmware/devicetree/"; + if (id->find(dropStr) == 0) + id->erase(0, dropStr.length()); + + return 0; + } + + /* Try to lookup ID as if the system where ACPI-based. */ + path = devPath + "/firmware_node/path"; + if (stat(path.c_str(), &statbuf) == 0) { + std::ifstream file(path.c_str()); + if (!file.is_open()) + return -EINVAL; + + std::getline(file, *id); + file.close(); + + return 0; + } + + return -ENODEV; +} + /** * \fn alignDown(unsigned int value, unsigned int alignment) * \brief Align \a value down to \a alignment From patchwork Mon Aug 3 21:17:29 2020 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: 9159 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 50305BD87A for ; Mon, 3 Aug 2020 21:18:05 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 0387661B3B; Mon, 3 Aug 2020 23:18:05 +0200 (CEST) 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 96E4460398 for ; Mon, 3 Aug 2020 23:18:02 +0200 (CEST) X-Halon-ID: 9e259e50-d5ce-11ea-86ee-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (p54ac52a8.dip0.t-ipconnect.de [84.172.82.168]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 9e259e50-d5ce-11ea-86ee-0050569116f7; Mon, 03 Aug 2020 23:16:38 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 3 Aug 2020 23:17:29 +0200 Message-Id: <20200803211733.1037019-6-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200803211733.1037019-1-niklas.soderlund@ragnatech.se> References: <20200803211733.1037019-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v6 5/9] libcamera: camera_sensor: Generate a sensor ID X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Generate a constant and unique string ID for the sensor. The ID is generated from information from the firmware description of the camera image sensor. The ID is unique and persistent across reboots of the system and may be used as a camera ID. The CameraSensor is intended to be sub-classed for specific sensor modules in the future to enable more advanced use-cases. Controlling the ID is one such feature that is already needed by the VIMC sensor. As the VIMC sensor is a virtual pipeline its sensor is not described in the device firmware and a subclass of CameraSensor is needed to generate a ID for VIMC sensors. Signed-off-by: Niklas Söderlund --- * Changes since v5 - Use new utils:: helper. - Allow for subclassing * Changes since v4 - Fix spelling. * Changes since v3 - Update commit message. - Add description of how ID are generated to comment. --- include/libcamera/internal/camera_sensor.h | 3 ++ src/libcamera/camera_sensor.cpp | 40 +++++++++++++++++++ src/libcamera/pipeline/vimc/vimc.cpp | 19 ++++++++- test/camera-sensor.cpp | 3 +- test/libtest/vimc_sensor_test.h | 29 ++++++++++++++ .../v4l2_videodevice_test.cpp | 4 +- 6 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 test/libtest/vimc_sensor_test.h diff --git a/include/libcamera/internal/camera_sensor.h b/include/libcamera/internal/camera_sensor.h index 06c8292ca30129de..b3aaaeaf829d97c0 100644 --- a/include/libcamera/internal/camera_sensor.h +++ b/include/libcamera/internal/camera_sensor.h @@ -47,6 +47,7 @@ public: int init(); const std::string &model() const { return model_; } + const std::string &id() const { return id_; } const MediaEntity *entity() const { return entity_; } const std::vector &mbusCodes() const { return mbusCodes_; } const std::vector &sizes() const { return sizes_; } @@ -65,6 +66,7 @@ public: protected: std::string logPrefix() const override; + virtual std::string generateID() const; private: const MediaEntity *entity_; @@ -72,6 +74,7 @@ private: unsigned int pad_; std::string model_; + std::string id_; V4L2Subdevice::Formats formats_; Size resolution_; diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp index 350f49accad99c7b..282cedecaf28fb3c 100644 --- a/src/libcamera/camera_sensor.cpp +++ b/src/libcamera/camera_sensor.cpp @@ -204,6 +204,11 @@ int CameraSensor::init() if (ret < 0) return ret; + /* Generate a unique ID for the sensor. */ + id_ = generateID(); + if (id_.empty()) + return -EINVAL; + /* Retrieve and store the camera sensor properties. */ const ControlInfoMap &controls = subdev_->controls(); int32_t propertyValue; @@ -283,6 +288,16 @@ int CameraSensor::init() * \return The sensor model name */ +/** + * \fn CameraSensor::id() + * \brief Retrieve the sensor ID + * + * The sensor ID is a free-form string that uniquely identifies the sensor in + * the system. The ID satisfy the requirements to be used as a camera ID. + * + * \return The sensor ID + */ + /** * \fn CameraSensor::entity() * \brief Retrieve the sensor media entity @@ -541,4 +556,29 @@ std::string CameraSensor::logPrefix() const return "'" + entity_->name() + "'"; } +/** + * \brief Generate a sensor ID for the sensor + * + * The generated string satisfy the requirements to be used as ID for a camera. + * This default implementation retrieves the ID form the firmware ID associated + * with the sensors V4L2 subdevice, that meets this criteria. + * + * It is possible to override this function to allow for more advanced IDs to be + * generated for specific sensors. Any alternative implementation is responsible + * for that the generated ID satisfy the requirements to be used as a camera ID. + * + * \sa id() + * \return Sensor ID on success or empty string on failure + */ +std::string CameraSensor::generateID() const +{ + std::string id; + if (utils::tryLookupFirmwareID(subdev_->devicePath(), &id)) { + LOG(CameraSensor, Error) << "Can't get sensor ID from firmware"; + return {}; + } + + return id; +} + } /* namespace libcamera */ diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp index 4f461b928514022d..b3348ab5d987d506 100644 --- a/src/libcamera/pipeline/vimc/vimc.cpp +++ b/src/libcamera/pipeline/vimc/vimc.cpp @@ -38,6 +38,21 @@ namespace libcamera { LOG_DEFINE_CATEGORY(VIMC) +class VimcCameraSensor : public CameraSensor +{ +public: + VimcCameraSensor(const MediaEntity *entity) + : CameraSensor(entity) + { + } + +protected: + std::string generateID() const override + { + return "VIMC " + entity()->name(); + } +}; + class VimcCameraData : public CameraData { public: @@ -61,7 +76,7 @@ public: void bufferReady(FrameBuffer *buffer); MediaDevice *media_; - CameraSensor *sensor_; + VimcCameraSensor *sensor_; V4L2Subdevice *debayer_; V4L2Subdevice *scaler_; V4L2VideoDevice *video_; @@ -457,7 +472,7 @@ int VimcCameraData::init() return ret; /* Create and open the camera sensor, debayer, scaler and video device. */ - sensor_ = new CameraSensor(media_->getEntityByName("Sensor B")); + sensor_ = new VimcCameraSensor(media_->getEntityByName("Sensor B")); ret = sensor_->init(); if (ret) return ret; diff --git a/test/camera-sensor.cpp b/test/camera-sensor.cpp index 8c7fd1d2d4445db3..50157b234fd40933 100644 --- a/test/camera-sensor.cpp +++ b/test/camera-sensor.cpp @@ -17,6 +17,7 @@ #include "libcamera/internal/v4l2_subdevice.h" #include "test.h" +#include "vimc_sensor_test.h" using namespace std; using namespace libcamera; @@ -50,7 +51,7 @@ protected: return TestFail; } - sensor_ = new CameraSensor(entity); + sensor_ = new TestVimcCameraSensor(entity); if (sensor_->init() < 0) { cerr << "Unable to initialise camera sensor" << endl; return TestFail; diff --git a/test/libtest/vimc_sensor_test.h b/test/libtest/vimc_sensor_test.h new file mode 100644 index 0000000000000000..1454a1c310f0dc9c --- /dev/null +++ b/test/libtest/vimc_sensor_test.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020, Google Inc. + * + * vimc_sensor_test.h - vimc_sensor test class + */ +#ifndef __LIBCAMERA_VIMC_SENSOR_TEST_H__ +#define __LIBCAMERA_VIMC_SENSOR_TEST_H__ + +#include "libcamera/internal/camera_sensor.h" + +using namespace libcamera; + +class TestVimcCameraSensor : public CameraSensor +{ +public: + TestVimcCameraSensor(const MediaEntity *entity) + : CameraSensor(entity) + { + } + +protected: + std::string generateID() const override + { + return "VIMC " + entity()->name(); + } +}; + +#endif /* __LIBCAMERA_VIMC_SENSOR_TEST_H__ */ diff --git a/test/v4l2_videodevice/v4l2_videodevice_test.cpp b/test/v4l2_videodevice/v4l2_videodevice_test.cpp index f23aaf8f514bc050..c7a3479963be9b78 100644 --- a/test/v4l2_videodevice/v4l2_videodevice_test.cpp +++ b/test/v4l2_videodevice/v4l2_videodevice_test.cpp @@ -12,6 +12,8 @@ #include "libcamera/internal/device_enumerator.h" #include "libcamera/internal/media_device.h" +#include "vimc_sensor_test.h" + #include "v4l2_videodevice_test.h" using namespace std; @@ -61,7 +63,7 @@ int V4L2VideoDeviceTest::init() return TestFail; if (driver_ == "vimc") { - sensor_ = new CameraSensor(media_->getEntityByName("Sensor A")); + sensor_ = new TestVimcCameraSensor(media_->getEntityByName("Sensor A")); if (sensor_->init()) return TestFail; From patchwork Mon Aug 3 21:17:30 2020 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: 9160 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 64F57BD87A for ; Mon, 3 Aug 2020 21:18:06 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 426EE61813; Mon, 3 Aug 2020 23:18:06 +0200 (CEST) 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 D6C8B61A06 for ; Mon, 3 Aug 2020 23:18:03 +0200 (CEST) X-Halon-ID: 9ead72f3-d5ce-11ea-86ee-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (p54ac52a8.dip0.t-ipconnect.de [84.172.82.168]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 9ead72f3-d5ce-11ea-86ee-0050569116f7; Mon, 03 Aug 2020 23:16:39 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 3 Aug 2020 23:17:30 +0200 Message-Id: <20200803211733.1037019-7-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200803211733.1037019-1-niklas.soderlund@ragnatech.se> References: <20200803211733.1037019-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v6 6/9] libcamera: pipelines: Use sensor ID as camera name X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Use the CameraSensor ID as the camera name in pipelines that uses a CameraSensors, this is done in preparation of turning the camera name into an ID. The CameraSensor ID meets the requirements that will be put on camera ID. Before this change example of camera names: * OF based systems ov5695 7-0036 ov2685 7-003c * ACPI based systems ov13858 8-0010 ov5670 10-0036 * VIMC VIMC Sensor B After this change the same cameras are: * OF based systems base/i2c@ff160000/camera@36 base/i2c@ff160000/camera@3c * ACPI based systems \_SB_.PCI0.I2C2.CAM0 \_SB_.PCI0.I2C4.CAM1 * VIMC VIMC Sensor B Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi --- src/libcamera/pipeline/ipu3/ipu3.cpp | 7 +++---- src/libcamera/pipeline/raspberrypi/raspberrypi.cpp | 3 ++- src/libcamera/pipeline/rkisp1/rkisp1.cpp | 2 +- src/libcamera/pipeline/simple/simple.cpp | 2 +- src/libcamera/pipeline/vimc/vimc.cpp | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index c1f9fdf1013c7ec0..c300f570d727e03e 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -805,10 +805,9 @@ int PipelineHandlerIPU3::registerCameras() &IPU3CameraData::imguOutputBufferReady); /* Create and register the Camera instance. */ - std::string cameraName = cio2->sensor()->entity()->name(); - std::shared_ptr camera = Camera::create(this, - cameraName, - streams); + std::string cameraName = cio2->sensor()->id(); + std::shared_ptr camera = + Camera::create(this, cameraName, streams); registerCamera(std::move(camera), std::move(data)); diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp index 82a0a4dfd6824fce..c55d7325cd44d6cb 100644 --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp @@ -972,7 +972,8 @@ bool PipelineHandlerRPi::match(DeviceEnumerator *enumerator) streams.insert(&data->isp_[Isp::Stats]); /* Create and register the camera. */ - std::shared_ptr camera = Camera::create(this, data->sensor_->model(), streams); + std::shared_ptr camera = + Camera::create(this, data->sensor_->id(), streams); registerCamera(std::move(camera), std::move(data)); return true; diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp index 52a0d862417cc4ec..94561062c2b9d4fc 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp @@ -971,7 +971,7 @@ int PipelineHandlerRkISP1::createCamera(MediaEntity *sensor) std::set streams{ &data->stream_ }; std::shared_ptr camera = - Camera::create(this, sensor->name(), streams); + Camera::create(this, data->sensor_->id(), streams); registerCamera(std::move(camera), std::move(data)); return 0; diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp index 0bab5af86f05d63c..eb72e3b8a2996342 100644 --- a/src/libcamera/pipeline/simple/simple.cpp +++ b/src/libcamera/pipeline/simple/simple.cpp @@ -815,7 +815,7 @@ bool SimplePipelineHandler::match(DeviceEnumerator *enumerator) continue; std::shared_ptr camera = - Camera::create(this, data->sensor_->entity()->name(), + Camera::create(this, data->sensor_->id(), data->streams()); registerCamera(std::move(camera), std::move(data)); } diff --git a/src/libcamera/pipeline/vimc/vimc.cpp b/src/libcamera/pipeline/vimc/vimc.cpp index b3348ab5d987d506..9cea731f2202d916 100644 --- a/src/libcamera/pipeline/vimc/vimc.cpp +++ b/src/libcamera/pipeline/vimc/vimc.cpp @@ -447,9 +447,9 @@ bool PipelineHandlerVimc::match(DeviceEnumerator *enumerator) return false; /* Create and register the camera. */ - std::string name{ "VIMC " + data->sensor_->model() }; std::set streams{ &data->stream_ }; - std::shared_ptr camera = Camera::create(this, name, streams); + std::shared_ptr camera + = Camera::create(this, data->sensor_->id(), streams); registerCamera(std::move(camera), std::move(data)); return true; From patchwork Mon Aug 3 21:17:31 2020 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: 9161 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 88194BD87B for ; Mon, 3 Aug 2020 21:18:06 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 5CA3B61B49; Mon, 3 Aug 2020 23:18:06 +0200 (CEST) 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 A0B3761A06 for ; Mon, 3 Aug 2020 23:18:04 +0200 (CEST) X-Halon-ID: 9f6de2f8-d5ce-11ea-86ee-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (p54ac52a8.dip0.t-ipconnect.de [84.172.82.168]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 9f6de2f8-d5ce-11ea-86ee-0050569116f7; Mon, 03 Aug 2020 23:16:40 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 3 Aug 2020 23:17:31 +0200 Message-Id: <20200803211733.1037019-8-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200803211733.1037019-1-niklas.soderlund@ragnatech.se> References: <20200803211733.1037019-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v6 7/9] libcamera: pipeline: uvcvideo: Generate unique camera names X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Generate camera names that are unique and persistent between system resets. The name is constructed from the USB device information as well as the USB controller on the host. Before this change example of camera names: Venus USB2.0 Camera: Venus USB2 Logitech Webcam C930e After this change the same cameras are: \_SB_.PCI0.RP05.PXSX-2.1.1:1.0-0ac8:3420 \_SB_.PCI0.RP05.PXSX-2.4:1.0-046d:0843 On OF-based system: base/soc/usb@7e980000/usb-port@1-1.3:1.0-0ac8:3420 Signed-off-by: Niklas Söderlund --- * Changes since v5 - New algorithm to generate IDs. * Changes since v3 - Switch argument to generateName() to UVCCameraData pointer. --- src/libcamera/pipeline/uvcvideo/uvcvideo.cpp | 76 +++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp index 93e3dc17e3a7105e..6a997bb5937a4a9c 100644 --- a/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp +++ b/src/libcamera/pipeline/uvcvideo/uvcvideo.cpp @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -81,6 +82,8 @@ public: bool match(DeviceEnumerator *enumerator) override; private: + std::string generateID(const UVCCameraData *data); + int processControl(ControlList *controls, unsigned int id, const ControlValue &value); int processControls(UVCCameraData *data, Request *request); @@ -379,6 +382,71 @@ int PipelineHandlerUVC::queueRequestDevice(Camera *camera, Request *request) return 0; } +std::string PipelineHandlerUVC::generateID(const UVCCameraData *data) +{ + const std::string path = data->video_->devicePath(); + + /* Creata a device ID from the USB devices vendor and product ID. */ + std::string deviceId; + for (const std::string &name : { "idVendor", "idProduct" }) { + std::ifstream file(path + "/../" + name); + + if (!file.is_open()) + return {}; + + std::string value; + std::getline(file, value); + file.close(); + + deviceId += value + (deviceId.empty() ? ":" : ""); + } + + /* + * Create a USB ID from the device path which has the known format: + * + * bus , "-", ports, ":", config, ".", interface ; + * bus = number ; + * ports = port, [ ".", ports ] ; + * port = number ; + * config = number ; + * interface = number ; + * + * Example: 3-2.4:1.0 + * + * The bus is not guaranteed to be stable and needs to be stripped from + * the USB ID. The final USB ID is built up of the ports, config and + * interface properties. + * + * Example 2.4:1.0. + */ + std::string usbId = basename(path.c_str()); + usbId = usbId.substr(usbId.find('-') + 1, std::string::npos); + + /* Create a controller ID from first device described in firmware. */ + std::string controllerId; + std::string searchPath = path; + while (true) { + searchPath += "/.."; + char *realPath = realpath(searchPath.c_str(), nullptr); + if (!realPath) { + LOG(UVC, Error) << "Failed to lookup " << searchPath; + return {}; + } + searchPath = realPath; + free(realPath); + + if (searchPath.empty() || searchPath == "/") { + LOG(UVC, Error) << "Can not find controller ID"; + return {}; + } + + if (!utils::tryLookupFirmwareID(searchPath, &controllerId)) + break; + } + + return controllerId + "-" + usbId + "-" + deviceId; +} + bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator) { MediaDevice *media; @@ -405,8 +473,14 @@ bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator) return false; /* Create and register the camera. */ + std::string id = generateID(data.get()); + if (id.empty()) { + LOG(UVC, Error) << "Failed to generate camera ID"; + return false; + } + std::set streams{ &data->stream_ }; - std::shared_ptr camera = Camera::create(this, media->model(), streams); + std::shared_ptr camera = Camera::create(this, id, streams); registerCamera(std::move(camera), std::move(data)); /* Enable hot-unplug notifications. */ From patchwork Mon Aug 3 21:17:32 2020 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: 9162 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id A63D7BD87A for ; Mon, 3 Aug 2020 21:18:08 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 8499A61AC3; Mon, 3 Aug 2020 23:18:08 +0200 (CEST) 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 168F360905 for ; Mon, 3 Aug 2020 23:18:06 +0200 (CEST) X-Halon-ID: 9fd4e5cc-d5ce-11ea-86ee-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (p54ac52a8.dip0.t-ipconnect.de [84.172.82.168]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id 9fd4e5cc-d5ce-11ea-86ee-0050569116f7; Mon, 03 Aug 2020 23:16:41 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 3 Aug 2020 23:17:32 +0200 Message-Id: <20200803211733.1037019-9-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200803211733.1037019-1-niklas.soderlund@ragnatech.se> References: <20200803211733.1037019-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v6 8/9] libcamera: camera: Rename name() to id() X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Rename Camera::name() to camera::id() to better describe what it represents, a unique and stable ID for the camera. While at it improve the documentation for the camera ID to describe it needs to be stable for a camera between resets of the system. Signed-off-by: Niklas Söderlund --- include/libcamera/camera.h | 6 +-- src/android/camera_device.cpp | 4 +- src/cam/main.cpp | 8 ++-- src/gstreamer/gstlibcameraprovider.cpp | 4 +- src/gstreamer/gstlibcamerasrc.cpp | 6 +-- src/libcamera/camera.cpp | 40 ++++++++++++------- src/libcamera/camera_controls.cpp | 2 +- src/libcamera/camera_manager.cpp | 16 ++++---- src/libcamera/framebuffer_allocator.cpp | 2 +- src/libcamera/pipeline/ipu3/ipu3.cpp | 5 +-- .../pipeline/raspberrypi/raspberrypi.cpp | 4 +- src/libcamera/pipeline/rkisp1/rkisp1.cpp | 14 +++---- src/qcam/dng_writer.cpp | 4 +- src/qcam/main_window.cpp | 18 ++++----- src/v4l2/v4l2_camera_proxy.cpp | 2 +- test/pipeline/ipu3/ipu3_pipeline_test.cpp | 2 +- test/pipeline/rkisp1/rkisp1_pipeline_test.cpp | 2 +- 17 files changed, 74 insertions(+), 65 deletions(-) diff --git a/include/libcamera/camera.h b/include/libcamera/camera.h index 7dd23d75864ef2db..48d88d64a0a94050 100644 --- a/include/libcamera/camera.h +++ b/include/libcamera/camera.h @@ -71,13 +71,13 @@ class Camera final : public Object, public std::enable_shared_from_this { public: static std::shared_ptr create(PipelineHandler *pipe, - const std::string &name, + const std::string &id, const std::set &streams); Camera(const Camera &) = delete; Camera &operator=(const Camera &) = delete; - const std::string &name() const; + const std::string &id() const; Signal bufferCompleted; Signal requestCompleted; @@ -100,7 +100,7 @@ public: int stop(); private: - Camera(PipelineHandler *pipe, const std::string &name, + Camera(PipelineHandler *pipe, const std::string &id, const std::set &streams); ~Camera(); diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp index b49d6681e5a52d32..c3f24dbd9d540648 100644 --- a/src/android/camera_device.cpp +++ b/src/android/camera_device.cpp @@ -1012,7 +1012,7 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list) int ret = camera_->configure(config_.get()); if (ret) { LOG(HAL, Error) << "Failed to configure camera '" - << camera_->name() << "'"; + << camera_->id() << "'"; return ret; } @@ -1180,7 +1180,7 @@ void CameraDevice::requestComplete(Request *request) std::string CameraDevice::logPrefix() const { - return "'" + camera_->name() + "'"; + return "'" + camera_->id() + "'"; } void CameraDevice::notifyShutter(uint32_t frameNumber, uint64_t timestamp) diff --git a/src/cam/main.cpp b/src/cam/main.cpp index ec59e9eaf1176a94..6791e57bfdea05b2 100644 --- a/src/cam/main.cpp +++ b/src/cam/main.cpp @@ -118,7 +118,7 @@ int CamApp::init(int argc, char **argv) return -EINVAL; } - std::cout << "Using camera " << camera_->name() << std::endl; + std::cout << "Using camera " << camera_->id() << std::endl; ret = prepareConfig(); if (ret) @@ -322,12 +322,12 @@ int CamApp::infoConfiguration() void CamApp::cameraAdded(std::shared_ptr cam) { - std::cout << "Camera Added: " << cam->name() << std::endl; + std::cout << "Camera Added: " << cam->id() << std::endl; } void CamApp::cameraRemoved(std::shared_ptr cam) { - std::cout << "Camera Removed: " << cam->name() << std::endl; + std::cout << "Camera Removed: " << cam->id() << std::endl; } int CamApp::run() @@ -339,7 +339,7 @@ int CamApp::run() unsigned int index = 1; for (const std::shared_ptr &cam : cm_->cameras()) { - std::cout << index << ": " << cam->name() << std::endl; + std::cout << index << ": " << cam->id() << std::endl; index++; } } diff --git a/src/gstreamer/gstlibcameraprovider.cpp b/src/gstreamer/gstlibcameraprovider.cpp index 914ed4fb1612b8c9..840e87a3d8daeae4 100644 --- a/src/gstreamer/gstlibcameraprovider.cpp +++ b/src/gstreamer/gstlibcameraprovider.cpp @@ -127,7 +127,7 @@ static GstDevice * gst_libcamera_device_new(const std::shared_ptr &camera) { g_autoptr(GstCaps) caps = gst_caps_new_empty(); - const gchar *name = camera->name().c_str(); + const gchar *name = camera->id().c_str(); StreamRoles roles; roles.push_back(StreamRole::VideoRecording); @@ -189,7 +189,7 @@ gst_libcamera_provider_probe(GstDeviceProvider *provider) } for (const std::shared_ptr &camera : cm->cameras()) { - GST_INFO_OBJECT(self, "Found camera '%s'", camera->name().c_str()); + GST_INFO_OBJECT(self, "Found camera '%s'", camera->id().c_str()); devices = g_list_append(devices, g_object_ref_sink(gst_libcamera_device_new(camera))); } diff --git a/src/gstreamer/gstlibcamerasrc.cpp b/src/gstreamer/gstlibcamerasrc.cpp index 9755922ad59b22f6..0c28ae3f28529df2 100644 --- a/src/gstreamer/gstlibcamerasrc.cpp +++ b/src/gstreamer/gstlibcamerasrc.cpp @@ -241,12 +241,12 @@ gst_libcamera_src_open(GstLibcameraSrc *self) cam = cm->cameras()[0]; } - GST_INFO_OBJECT(self, "Using camera named '%s'", cam->name().c_str()); + GST_INFO_OBJECT(self, "Using camera '%s'", cam->id().c_str()); ret = cam->acquire(); if (ret) { GST_ELEMENT_ERROR(self, RESOURCE, BUSY, - ("Camera name '%s' is already in use.", cam->name().c_str()), + ("Camera '%s' is already in use.", cam->id().c_str()), ("libcamera::Camera::acquire() failed: %s", g_strerror(ret))); return false; } @@ -495,7 +495,7 @@ gst_libcamera_src_close(GstLibcameraSrc *self) ret = state->cam_->release(); if (ret) { GST_ELEMENT_WARNING(self, RESOURCE, BUSY, - ("Camera name '%s' is still in use.", state->cam_->name().c_str()), + ("Camera '%s' is still in use.", state->cam_->id().c_str()), ("libcamera::Camera.release() failed: %s", g_strerror(-ret))); } diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp index 99cb5048ee06e3d3..a547542d1b67cc2b 100644 --- a/src/libcamera/camera.cpp +++ b/src/libcamera/camera.cpp @@ -265,7 +265,7 @@ public: CameraRunning, }; - Private(PipelineHandler *pipe, const std::string &name, + Private(PipelineHandler *pipe, const std::string &id, const std::set &streams); ~Private(); @@ -277,7 +277,7 @@ public: void setState(State state); std::shared_ptr pipe_; - std::string name_; + std::string id_; std::set streams_; std::set activeStreams_; @@ -286,9 +286,9 @@ private: std::atomic state_; }; -Camera::Private::Private(PipelineHandler *pipe, const std::string &name, +Camera::Private::Private(PipelineHandler *pipe, const std::string &id, const std::set &streams) - : pipe_(pipe->shared_from_this()), name_(name), streams_(streams), + : pipe_(pipe->shared_from_this()), id_(id), streams_(streams), disconnected_(false), state_(CameraAvailable) { } @@ -450,15 +450,25 @@ void Camera::Private::setState(State state) /** * \brief Create a camera instance * \param[in] pipe The pipeline handler responsible for the camera device - * \param[in] name The name of the camera device + * \param[in] id The ID of the camera device * \param[in] streams Array of streams the camera provides * - * The caller is responsible for guaranteeing unicity of the camera name. + * The caller is responsible for guaranteeing a stable and unique camera ID. For + * an ID to be stable it must be the same each time the pipeline handler creates + * it, even between system resets. Parameters that are enumerated at system + * startup such as bus parameters which might be enumerated differently are + * therefor not possible to use in the ID. For an ID to be unique no pipeline + * should generate an ID that could conflict, either with IDs from the same + * pipeline handle or any other. + * + * Pipeline handlers that use a CameraSensor may use the CameraSensor::id() to + * generate and ID which satisfies the criteria of a stable and unique camera + * ID. * * \return A shared pointer to the newly created camera object */ std::shared_ptr Camera::create(PipelineHandler *pipe, - const std::string &name, + const std::string &id, const std::set &streams) { struct Deleter : std::default_delete { @@ -468,19 +478,19 @@ std::shared_ptr Camera::create(PipelineHandler *pipe, } }; - Camera *camera = new Camera(pipe, name, streams); + Camera *camera = new Camera(pipe, id, streams); return std::shared_ptr(camera, Deleter()); } /** - * \brief Retrieve the name of the camera + * \brief Retrieve the ID of the camera * \context This function is \threadsafe. - * \return Name of the camera device + * \return ID of the camera device */ -const std::string &Camera::name() const +const std::string &Camera::id() const { - return p_->name_; + return p_->id_; } /** @@ -506,9 +516,9 @@ const std::string &Camera::name() const * application API calls by returning errors immediately. */ -Camera::Camera(PipelineHandler *pipe, const std::string &name, +Camera::Camera(PipelineHandler *pipe, const std::string &id, const std::set &streams) - : p_(new Private(pipe, name, streams)) + : p_(new Private(pipe, id, streams)) { } @@ -530,7 +540,7 @@ Camera::~Camera() */ void Camera::disconnect() { - LOG(Camera, Debug) << "Disconnecting camera " << name(); + LOG(Camera, Debug) << "Disconnecting camera " << id(); p_->disconnect(); disconnected.emit(this); diff --git a/src/libcamera/camera_controls.cpp b/src/libcamera/camera_controls.cpp index 371f6d079e2d877c..cabdcf75c223fc3e 100644 --- a/src/libcamera/camera_controls.cpp +++ b/src/libcamera/camera_controls.cpp @@ -36,7 +36,7 @@ CameraControlValidator::CameraControlValidator(Camera *camera) const std::string &CameraControlValidator::name() const { - return camera_->name(); + return camera_->id(); } /** diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp index c45bf33fdc1ef01b..76543b6aac8df9c4 100644 --- a/src/libcamera/camera_manager.cpp +++ b/src/libcamera/camera_manager.cpp @@ -181,10 +181,10 @@ void CameraManager::Private::addCamera(std::shared_ptr camera, MutexLocker locker(mutex_); for (std::shared_ptr c : cameras_) { - if (c->name() == camera->name()) { + if (c->id() == camera->id()) { LOG(Camera, Warning) - << "Registering camera with duplicate name '" - << camera->name() << "'"; + << "Registering camera with duplicate ID '" + << camera->id() << "'"; break; } } @@ -208,7 +208,7 @@ void CameraManager::Private::removeCamera(Camera *camera) return; LOG(Camera, Debug) - << "Unregistering camera '" << camera->name() << "'"; + << "Unregistering camera '" << camera->id() << "'"; auto iter_d = std::find_if(camerasByDevnum_.begin(), camerasByDevnum_.end(), [camera](const std::pair> &p) { @@ -329,8 +329,8 @@ std::vector> CameraManager::cameras() const } /** - * \brief Get a camera based on name - * \param[in] name Name of camera to get + * \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. @@ -339,12 +339,12 @@ std::vector> CameraManager::cameras() const * * \return Shared pointer to Camera object or nullptr if camera not found */ -std::shared_ptr CameraManager::get(const std::string &name) +std::shared_ptr CameraManager::get(const std::string &id) { MutexLocker locker(p_->mutex_); for (std::shared_ptr camera : p_->cameras_) { - if (camera->name() == name) + if (camera->id() == id) return camera; } diff --git a/src/libcamera/framebuffer_allocator.cpp b/src/libcamera/framebuffer_allocator.cpp index 252191ba234c5450..2fbba37a1b0b7254 100644 --- a/src/libcamera/framebuffer_allocator.cpp +++ b/src/libcamera/framebuffer_allocator.cpp @@ -95,7 +95,7 @@ int FrameBufferAllocator::allocate(Stream *stream) int ret = camera_->exportFrameBuffers(stream, &buffers_[stream]); if (ret == -EINVAL) LOG(Allocator, Error) - << "Stream is not part of " << camera_->name() + << "Stream is not part of " << camera_->id() << " active configuration"; return ret; } diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp index c300f570d727e03e..25f890947b660ecc 100644 --- a/src/libcamera/pipeline/ipu3/ipu3.cpp +++ b/src/libcamera/pipeline/ipu3/ipu3.cpp @@ -629,7 +629,7 @@ int PipelineHandlerIPU3::start(Camera *camera) error: freeBuffers(camera); - LOG(IPU3, Error) << "Failed to start camera " << camera->name(); + LOG(IPU3, Error) << "Failed to start camera " << camera->id(); return ret; } @@ -642,8 +642,7 @@ void PipelineHandlerIPU3::stop(Camera *camera) ret |= data->imgu_->stop(); ret |= data->cio2_.stop(); if (ret) - LOG(IPU3, Warning) << "Failed to stop camera " - << camera->name(); + LOG(IPU3, Warning) << "Failed to stop camera " << camera->id(); freeBuffers(camera); } diff --git a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp index c55d7325cd44d6cb..eeaf335cbcd2f93f 100644 --- a/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp +++ b/src/libcamera/pipeline/raspberrypi/raspberrypi.cpp @@ -643,7 +643,7 @@ int PipelineHandlerRPi::configure(Camera *camera, CameraConfiguration *config) if (ret) return ret; - LOG(RPI, Info) << "Sensor: " << camera->name() + LOG(RPI, Info) << "Sensor: " << camera->id() << " - Selected mode: " << sensorFormat.toString(); /* @@ -793,7 +793,7 @@ int PipelineHandlerRPi::start(Camera *camera) ret = data->ipa_->start(); if (ret) { LOG(RPI, Error) - << "Failed to start IPA for " << camera->name(); + << "Failed to start IPA for " << camera->id(); stop(camera); return ret; } diff --git a/src/libcamera/pipeline/rkisp1/rkisp1.cpp b/src/libcamera/pipeline/rkisp1/rkisp1.cpp index 94561062c2b9d4fc..b7609cbc8f363135 100644 --- a/src/libcamera/pipeline/rkisp1/rkisp1.cpp +++ b/src/libcamera/pipeline/rkisp1/rkisp1.cpp @@ -798,7 +798,7 @@ int PipelineHandlerRkISP1::start(Camera *camera) if (ret) { freeBuffers(camera); LOG(RkISP1, Error) - << "Failed to start IPA " << camera->name(); + << "Failed to start IPA " << camera->id(); return ret; } @@ -809,7 +809,7 @@ int PipelineHandlerRkISP1::start(Camera *camera) data->ipa_->stop(); freeBuffers(camera); LOG(RkISP1, Error) - << "Failed to start parameters " << camera->name(); + << "Failed to start parameters " << camera->id(); return ret; } @@ -819,7 +819,7 @@ int PipelineHandlerRkISP1::start(Camera *camera) data->ipa_->stop(); freeBuffers(camera); LOG(RkISP1, Error) - << "Failed to start statistics " << camera->name(); + << "Failed to start statistics " << camera->id(); return ret; } @@ -831,7 +831,7 @@ int PipelineHandlerRkISP1::start(Camera *camera) freeBuffers(camera); LOG(RkISP1, Error) - << "Failed to start camera " << camera->name(); + << "Failed to start camera " << camera->id(); } activeCamera_ = camera; @@ -870,17 +870,17 @@ void PipelineHandlerRkISP1::stop(Camera *camera) ret = video_->streamOff(); if (ret) LOG(RkISP1, Warning) - << "Failed to stop camera " << camera->name(); + << "Failed to stop camera " << camera->id(); ret = stat_->streamOff(); if (ret) LOG(RkISP1, Warning) - << "Failed to stop statistics " << camera->name(); + << "Failed to stop statistics " << camera->id(); ret = param_->streamOff(); if (ret) LOG(RkISP1, Warning) - << "Failed to stop parameters " << camera->name(); + << "Failed to stop parameters " << camera->id(); data->ipa_->stop(); diff --git a/src/qcam/dng_writer.cpp b/src/qcam/dng_writer.cpp index 8fb9681c2b4fb5e8..65fbd409cfe72bf4 100644 --- a/src/qcam/dng_writer.cpp +++ b/src/qcam/dng_writer.cpp @@ -386,8 +386,8 @@ int DNGWriter::write(const char *filename, const Camera *camera, TIFFSetField(tif, TIFFTAG_DNGBACKWARDVERSION, version); TIFFSetField(tif, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB); TIFFSetField(tif, TIFFTAG_MAKE, "libcamera"); - TIFFSetField(tif, TIFFTAG_MODEL, camera->name().c_str()); - TIFFSetField(tif, TIFFTAG_UNIQUECAMERAMODEL, camera->name().c_str()); + TIFFSetField(tif, TIFFTAG_MODEL, camera->id().c_str()); + TIFFSetField(tif, TIFFTAG_UNIQUECAMERAMODEL, camera->id().c_str()); TIFFSetField(tif, TIFFTAG_SOFTWARE, "qcam"); TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index 13a4fefe89ae7525..526e50f48fd36577 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -169,7 +169,7 @@ int MainWindow::createToolbars() this, &MainWindow::switchCamera); for (const std::shared_ptr &cam : cm_->cameras()) - cameraCombo_->addItem(QString::fromStdString(cam->name())); + cameraCombo_->addItem(QString::fromStdString(cam->id())); toolbar_->addWidget(cameraCombo_); @@ -241,11 +241,11 @@ void MainWindow::switchCamera(int index) const std::shared_ptr &cam = cameras[index]; if (cam->acquire()) { - qInfo() << "Failed to acquire camera" << cam->name().c_str(); + qInfo() << "Failed to acquire camera" << cam->id().c_str(); return; } - qInfo() << "Switching to camera" << cam->name().c_str(); + qInfo() << "Switching to camera" << cam->id().c_str(); /* * Stop the capture session, release the current camera, replace it with @@ -266,11 +266,11 @@ std::string MainWindow::chooseCamera() /* If only one camera is available, use it automatically. */ if (cm_->cameras().size() == 1) - return cm_->cameras()[0]->name(); + return cm_->cameras()[0]->id(); /* Present a dialog box to pick a camera. */ for (const std::shared_ptr &cam : cm_->cameras()) - cameras.append(QString::fromStdString(cam->name())); + cameras.append(QString::fromStdString(cam->id())); QString name = QInputDialog::getItem(this, "Select Camera", "Camera:", cameras, 0, @@ -582,7 +582,7 @@ void MainWindow::processHotplug(HotplugEvent *e) HotplugEvent::PlugEvent event = e->hotplugEvent(); if (event == HotplugEvent::HotPlug) { - cameraCombo_->addItem(QString::fromStdString(camera->name())); + cameraCombo_->addItem(QString::fromStdString(camera->id())); } else if (event == HotplugEvent::HotUnplug) { /* Check if the currently-streaming camera is removed. */ if (camera == camera_.get()) { @@ -592,14 +592,14 @@ void MainWindow::processHotplug(HotplugEvent *e) cameraCombo_->setCurrentIndex(0); } - int camIndex = cameraCombo_->findText(QString::fromStdString(camera->name())); + int camIndex = cameraCombo_->findText(QString::fromStdString(camera->id())); cameraCombo_->removeItem(camIndex); } } void MainWindow::addCamera(std::shared_ptr camera) { - qInfo() << "Adding new camera:" << camera->name().c_str(); + qInfo() << "Adding new camera:" << camera->id().c_str(); QCoreApplication::postEvent(this, new HotplugEvent(std::move(camera), HotplugEvent::HotPlug)); @@ -607,7 +607,7 @@ void MainWindow::addCamera(std::shared_ptr camera) void MainWindow::removeCamera(std::shared_ptr camera) { - qInfo() << "Removing camera:" << camera->name().c_str(); + qInfo() << "Removing camera:" << camera->id().c_str(); QCoreApplication::postEvent(this, new HotplugEvent(std::move(camera), HotplugEvent::HotUnplug)); diff --git a/src/v4l2/v4l2_camera_proxy.cpp b/src/v4l2/v4l2_camera_proxy.cpp index 50ab7e66cdc02fb1..63affaeec1b3af11 100644 --- a/src/v4l2/v4l2_camera_proxy.cpp +++ b/src/v4l2/v4l2_camera_proxy.cpp @@ -189,7 +189,7 @@ void V4L2CameraProxy::querycap(std::shared_ptr camera) utils::strlcpy(reinterpret_cast(capabilities_.driver), driver.c_str(), sizeof(capabilities_.driver)); - utils::strlcpy(reinterpret_cast(capabilities_.card), camera->name().c_str(), + utils::strlcpy(reinterpret_cast(capabilities_.card), camera->id().c_str(), sizeof(capabilities_.card)); utils::strlcpy(reinterpret_cast(capabilities_.bus_info), bus_info.c_str(), sizeof(capabilities_.bus_info)); diff --git a/test/pipeline/ipu3/ipu3_pipeline_test.cpp b/test/pipeline/ipu3/ipu3_pipeline_test.cpp index 34998f8f6d04473f..9e647af5fdf8ee7f 100644 --- a/test/pipeline/ipu3/ipu3_pipeline_test.cpp +++ b/test/pipeline/ipu3/ipu3_pipeline_test.cpp @@ -106,7 +106,7 @@ int IPU3PipelineTest::run() { auto cameras = cameraManager_->cameras(); for (const std::shared_ptr &cam : cameras) - cout << "Found camera '" << cam->name() << "'" << endl; + cout << "Found camera '" << cam->id() << "'" << endl; if (cameras.size() != sensors_) { cerr << cameras.size() << " cameras registered, but " << sensors_ diff --git a/test/pipeline/rkisp1/rkisp1_pipeline_test.cpp b/test/pipeline/rkisp1/rkisp1_pipeline_test.cpp index b6678ce76e9af193..acaf3c33b529d31d 100644 --- a/test/pipeline/rkisp1/rkisp1_pipeline_test.cpp +++ b/test/pipeline/rkisp1/rkisp1_pipeline_test.cpp @@ -95,7 +95,7 @@ int RKISP1PipelineTest::run() { auto cameras = cameraManager_->cameras(); for (const std::shared_ptr &cam : cameras) - cout << "Found camera '" << cam->name() << "'" << endl; + cout << "Found camera '" << cam->id() << "'" << endl; if (cameras.size() != sensors_) { cerr << cameras.size() << " cameras registered, but " << sensors_ From patchwork Mon Aug 3 21:17:33 2020 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: 9163 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id C8F69BD87B for ; Mon, 3 Aug 2020 21:18:08 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id A43E261B6E; Mon, 3 Aug 2020 23:18:08 +0200 (CEST) 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 CAA4F60905 for ; Mon, 3 Aug 2020 23:18:06 +0200 (CEST) X-Halon-ID: a0bfd3ab-d5ce-11ea-86ee-0050569116f7 Authorized-sender: niklas@soderlund.pp.se Received: from bismarck.berto.se (p54ac52a8.dip0.t-ipconnect.de [84.172.82.168]) by bin-vsp-out-03.atm.binero.net (Halon) with ESMTPA id a0bfd3ab-d5ce-11ea-86ee-0050569116f7; Mon, 03 Aug 2020 23:16:42 +0200 (CEST) From: =?utf-8?q?Niklas_S=C3=B6derlund?= To: libcamera-devel@lists.libcamera.org Date: Mon, 3 Aug 2020 23:17:33 +0200 Message-Id: <20200803211733.1037019-10-niklas.soderlund@ragnatech.se> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200803211733.1037019-1-niklas.soderlund@ragnatech.se> References: <20200803211733.1037019-1-niklas.soderlund@ragnatech.se> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v6 9/9] libcamera: camera_manager: Enforce unique camera IDs X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The camera ID is documented that it should be unique but it's not enforced. Change this by refusing to add cameras to the CameraManager that would create two cameras with the exact same ID. Signed-off-by: Niklas Söderlund Reviewed-by: Jacopo Mondi Reviewed-by: Kieran Bingham --- * Changes since v5 - Rename 'name' to 'id'. - Make error Fatal. * Changes since v4 - Update string in error message. * Changes since v3 - Update commit message. --- src/libcamera/camera_manager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp index 76543b6aac8df9c4..47d56256abd6d490 100644 --- a/src/libcamera/camera_manager.cpp +++ b/src/libcamera/camera_manager.cpp @@ -182,10 +182,10 @@ void CameraManager::Private::addCamera(std::shared_ptr camera, for (std::shared_ptr c : cameras_) { if (c->id() == camera->id()) { - LOG(Camera, Warning) - << "Registering camera with duplicate ID '" + LOG(Camera, Fatal) + << "Trying to register a camera with a duplicated ID '" << camera->id() << "'"; - break; + return; } }