Patch Detail
Show a patch.
GET /api/patches/1058/?format=api
{ "id": 1058, "url": "https://patchwork.libcamera.org/api/patches/1058/?format=api", "web_url": "https://patchwork.libcamera.org/patch/1058/", "project": { "id": 1, "url": "https://patchwork.libcamera.org/api/projects/1/?format=api", "name": "libcamera", "link_name": "libcamera", "list_id": "libcamera_core", "list_email": "libcamera-devel@lists.libcamera.org", "web_url": "", "scm_url": "", "webscm_url": "" }, "msgid": "<20190418141437.14014-12-laurent.pinchart@ideasonboard.com>", "date": "2019-04-18T14:14:35", "name": "[libcamera-devel,v3,11/13] libcamera: camera_sensor: Add a new class to model a camera sensor", "commit_ref": null, "pull_url": null, "state": "accepted", "archived": false, "hash": "74b2a231637198932161a7e9940e7e587b4d8818", "submitter": { "id": 2, "url": "https://patchwork.libcamera.org/api/people/2/?format=api", "name": "Laurent Pinchart", "email": "laurent.pinchart@ideasonboard.com" }, "delegate": null, "mbox": "https://patchwork.libcamera.org/patch/1058/mbox/", "series": [ { "id": 256, "url": "https://patchwork.libcamera.org/api/series/256/?format=api", "web_url": "https://patchwork.libcamera.org/project/libcamera/list/?series=256", "date": "2019-04-18T14:14:24", "name": "Rockchip ISP pipeline handler", "version": 3, "mbox": "https://patchwork.libcamera.org/series/256/mbox/" } ], "comments": "https://patchwork.libcamera.org/api/patches/1058/comments/", "check": "pending", "checks": "https://patchwork.libcamera.org/api/patches/1058/checks/", "tags": {}, "headers": { "Return-Path": "<laurent.pinchart@ideasonboard.com>", "Received": [ "from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id F10FD60DCC\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 18 Apr 2019 16:14:58 +0200 (CEST)", "from pendragon.bb.dnainternet.fi (81-175-216-236.bb.dnainternet.fi\n\t[81.175.216.236])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 8075A9D6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 18 Apr 2019 16:14:58 +0200 (CEST)" ], "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1555596898;\n\tbh=KuiuGC3BtLU7nlLQG9RL+BKdzoQ7+Gw34/lM9hw3dyk=;\n\th=From:To:Subject:Date:In-Reply-To:References:From;\n\tb=d83OPYdovefeqjkBodNrGdRlMLguwDE91oId/viaByI5Ro+g5rUTTCpg4zgtHzLZ9\n\tuU3lRF+KeV+UD+cOH7Gb2v8KZCUfTwWADrT+T1IZ5IPZ43D+O036FgVCqbAPr18Cep\n\tllXXhbQLwketX+6BjkTdHMFHka2W3w2mKHYKn/WM=", "From": "Laurent Pinchart <laurent.pinchart@ideasonboard.com>", "To": "libcamera-devel@lists.libcamera.org", "Date": "Thu, 18 Apr 2019 17:14:35 +0300", "Message-Id": "<20190418141437.14014-12-laurent.pinchart@ideasonboard.com>", "X-Mailer": "git-send-email 2.21.0", "In-Reply-To": "<20190418141437.14014-1-laurent.pinchart@ideasonboard.com>", "References": "<20190418141437.14014-1-laurent.pinchart@ideasonboard.com>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=UTF-8", "Content-Transfer-Encoding": "8bit", "Subject": "[libcamera-devel] [PATCH v3 11/13] libcamera: camera_sensor: Add a\n\tnew class to model a camera sensor", "X-BeenThere": "libcamera-devel@lists.libcamera.org", "X-Mailman-Version": "2.1.23", "Precedence": "list", "List-Id": "<libcamera-devel.lists.libcamera.org>", "List-Unsubscribe": "<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>", "List-Archive": "<https://lists.libcamera.org/pipermail/libcamera-devel/>", "List-Post": "<mailto:libcamera-devel@lists.libcamera.org>", "List-Help": "<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>", "List-Subscribe": "<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>", "X-List-Received-Date": "Thu, 18 Apr 2019 14:15:00 -0000" }, "content": "The CameraSensor class abstracts camera sensors and provides helper\nfunctions to ease interactions with them. It is currently limited to\nsensors that expose a single subdev, and offer the same frame sizes for\nall media bus codes, but will be extended to support more complex\nsensors as the needs arise.\n\nSigned-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\nReviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n---\nChanges since v1:\n\n- Add sensor entity function check\n- Sort the media bus codes\n- Remove the unneeded std::endl for LOG()\n- Improve documentation\n- Inherit from Loggable with the protected qualifier\n---\n src/libcamera/camera_sensor.cpp | 258 ++++++++++++++++++++++++++\n src/libcamera/include/camera_sensor.h | 56 ++++++\n src/libcamera/meson.build | 2 +\n 3 files changed, 316 insertions(+)\n create mode 100644 src/libcamera/camera_sensor.cpp\n create mode 100644 src/libcamera/include/camera_sensor.h", "diff": "diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp\nnew file mode 100644\nindex 000000000000..ca4dd0c92efa\n--- /dev/null\n+++ b/src/libcamera/camera_sensor.cpp\n@@ -0,0 +1,258 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2019, Google Inc.\n+ *\n+ * camera_sensor.cpp - A camera sensor\n+ */\n+\n+#include <algorithm>\n+#include <float.h>\n+#include <iomanip>\n+#include <limits.h>\n+#include <math.h>\n+\n+#include \"camera_sensor.h\"\n+#include \"formats.h\"\n+#include \"v4l2_subdevice.h\"\n+\n+/**\n+ * \\file camera_sensor.h\n+ * \\brief A camera sensor\n+ */\n+\n+namespace libcamera {\n+\n+LOG_DEFINE_CATEGORY(CameraSensor);\n+\n+/**\n+ * \\class CameraSensor\n+ * \\brief A camera sensor based on V4L2 subdevices\n+ *\n+ * The CameraSensor class eases handling of sensors for pipeline handlers by\n+ * hiding the details of the V4L2 subdevice kernel API and caching sensor\n+ * information.\n+ *\n+ * The implementation is currently limited to sensors that expose a single V4L2\n+ * subdevice with a single pad, and support the same frame sizes for all\n+ * supported media bus codes. It will be extended to support more complex\n+ * devices as the needs arise.\n+ */\n+\n+/**\n+ * \\brief Construct a CameraSensor\n+ * \\param[in] entity The media entity backing the camera sensor\n+ *\n+ * Once constructed the instance must be initialized with init().\n+ */\n+CameraSensor::CameraSensor(const MediaEntity *entity)\n+\t: entity_(entity)\n+{\n+\tsubdev_ = new V4L2Subdevice(entity);\n+}\n+\n+/**\n+ * \\brief Destroy a CameraSensor\n+ */\n+CameraSensor::~CameraSensor()\n+{\n+\tdelete subdev_;\n+}\n+\n+/**\n+ * \\brief Initialize the camera sensor instance\n+ *\n+ * This method performs the initialisation steps of the CameraSensor that may\n+ * fail. It shall be called once and only once after constructing the instance.\n+ *\n+ * \\return 0 on success or a negative error code otherwise\n+ */\n+int CameraSensor::init()\n+{\n+\tint ret;\n+\n+\tif (entity_->pads().size() != 1) {\n+\t\tLOG(CameraSensor, Error)\n+\t\t\t<< \"Sensors with more than one pad are not supported\";\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tif (entity_->function() != MEDIA_ENT_F_CAM_SENSOR) {\n+\t\tLOG(CameraSensor, Error)\n+\t\t\t<< \"Invalid sensor function 0x\"\n+\t\t\t<< std::hex << std::setfill('0') << std::setw(8)\n+\t\t\t<< entity_->function();\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tret = subdev_->open();\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\t/* Enumerate and cache media bus codes and sizes. */\n+\tconst FormatEnum formats = subdev_->formats(0);\n+\tif (formats.empty()) {\n+\t\tLOG(CameraSensor, Error) << \"No image format found\";\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tstd::transform(formats.begin(), formats.end(),\n+\t\t std::back_inserter(mbusCodes_),\n+\t\t [](decltype(*formats.begin()) f) { return f.first; });\n+\n+\t/*\n+\t * Extract the supported sizes from the first format as we only support\n+\t * sensors that offer the same frame sizes for all media bus codes.\n+\t * Verify this assumption and reject the sensor if it isn't true.\n+\t */\n+\tconst std::vector<SizeRange> &sizes = formats.begin()->second;\n+\tstd::transform(sizes.begin(), sizes.end(), std::back_inserter(sizes_),\n+\t\t [](const SizeRange &range) { return range.max; });\n+\n+\tfor (auto it = ++formats.begin(); it != formats.end(); ++it) {\n+\t\tif (it->second != sizes) {\n+\t\t\tLOG(CameraSensor, Error)\n+\t\t\t\t<< \"Frame sizes differ between media bus codes\";\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\n+\t/* Sort the media bus codes and sizes. */\n+\tstd::sort(mbusCodes_.begin(), mbusCodes_.end());\n+\tstd::sort(sizes_.begin(), sizes_.end());\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * \\fn CameraSensor::entity()\n+ * \\brief Retrieve the sensor media entity\n+ * \\return The sensor media entity\n+ */\n+\n+/**\n+ * \\fn CameraSensor::mbusCodes()\n+ * \\brief Retrieve the media bus codes supported by the camera sensor\n+ * \\return The supported media bus codes sorted in increasing order\n+ */\n+\n+/**\n+ * \\fn CameraSensor::sizes()\n+ * \\brief Retrieve the frame sizes supported by the camera sensor\n+ * \\return The supported frame sizes sorted in increasing order\n+ */\n+\n+/**\n+ * \\brief Retrieve the camera sensor resolution\n+ * \\return The camera sensor resolution in pixels\n+ */\n+const Size &CameraSensor::resolution() const\n+{\n+\t/*\n+\t * The sizes_ vector is sorted in ascending order, the resolution is\n+\t * thus the last element of the vector.\n+\t */\n+\treturn sizes_.back();\n+}\n+\n+/**\n+ * \\brief Retrieve the best sensor format for a desired output\n+ * \\param[in] mbusCodes The list of acceptable media bus codes\n+ * \\param[in] size The desired size\n+ *\n+ * Media bus codes are selected from \\a mbusCodes, which lists all acceptable\n+ * codes in decreasing order of preference. This method selects the first code\n+ * from the list that is supported by the sensor. If none of the desired codes\n+ * is supported, it returns an error.\n+ *\n+ * \\a size indicates the desired size at the output of the sensor. This method\n+ * selects the best size supported by the sensor according to the following\n+ * criteria.\n+ *\n+ * - The desired \\a size shall fit in the sensor output size to avoid the need\n+ * to up-scale.\n+ * - The sensor output size shall match the desired aspect ratio to avoid the\n+ * need to crop the field of view.\n+ * - The sensor output size shall be as small as possible to lower the required\n+ * bandwidth.\n+ *\n+ * The use of this method is optional, as the above criteria may not match the\n+ * needs of all pipeline handlers. Pipeline handlers may implement custom\n+ * sensor format selection when needed.\n+ *\n+ * The returned sensor output format is guaranteed to be acceptable by the\n+ * setFormat() method without any modification.\n+ *\n+ * \\return The best sensor output format matching the desired media bus codes\n+ * and size on success, or an empty format otherwise.\n+ */\n+V4L2SubdeviceFormat CameraSensor::getFormat(const std::vector<unsigned int> &mbusCodes,\n+\t\t\t\t\t const Size &size) const\n+{\n+\tV4L2SubdeviceFormat format{};\n+\n+\tfor (unsigned int code : mbusCodes_) {\n+\t\tif (std::any_of(mbusCodes.begin(), mbusCodes.end(),\n+\t\t\t\t[code](unsigned int c) { return c == code; })) {\n+\t\t\tformat.mbus_code = code;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tif (!format.mbus_code) {\n+\t\tLOG(CameraSensor, Debug) << \"No supported format found\";\n+\t\treturn format;\n+\t}\n+\n+\tunsigned int desiredArea = size.width * size.height;\n+\tunsigned int bestArea = UINT_MAX;\n+\tfloat desiredRatio = static_cast<float>(size.width) / size.height;\n+\tfloat bestRatio = FLT_MAX;\n+\tconst Size *bestSize = nullptr;\n+\n+\tfor (const Size &sz : sizes_) {\n+\t\tif (sz.width < size.width || sz.height < size.height)\n+\t\t\tcontinue;\n+\n+\t\tfloat ratio = static_cast<float>(sz.width) / sz.height;\n+\t\tfloat ratioDiff = fabsf(ratio - desiredRatio);\n+\t\tunsigned int area = sz.width * sz.height;\n+\t\tunsigned int areaDiff = area - desiredArea;\n+\n+\t\tif (ratioDiff > bestRatio)\n+\t\t\tcontinue;\n+\n+\t\tif (ratioDiff < bestRatio || areaDiff < bestArea) {\n+\t\t\tbestRatio = ratioDiff;\n+\t\t\tbestArea = areaDiff;\n+\t\t\tbestSize = &sz;\n+\t\t}\n+\t}\n+\n+\tif (!bestSize) {\n+\t\tLOG(CameraSensor, Debug) << \"No supported size found\";\n+\t\treturn format;\n+\t}\n+\n+\tformat.width = bestSize->width;\n+\tformat.height = bestSize->height;\n+\n+\treturn format;\n+}\n+\n+/**\n+ * \\brief Set the sensor output format\n+ * \\param[in] format The desired sensor output format\n+ *\n+ * \\return 0 on success or a negative error code otherwise\n+ */\n+int CameraSensor::setFormat(V4L2SubdeviceFormat *format)\n+{\n+\treturn subdev_->setFormat(0, format);\n+}\n+\n+std::string CameraSensor::logPrefix() const\n+{\n+\treturn \"'\" + subdev_->entity()->name() + \"'\";\n+}\n+\n+} /* namespace libcamera */\ndiff --git a/src/libcamera/include/camera_sensor.h b/src/libcamera/include/camera_sensor.h\nnew file mode 100644\nindex 000000000000..7f2f906be8df\n--- /dev/null\n+++ b/src/libcamera/include/camera_sensor.h\n@@ -0,0 +1,56 @@\n+/* SPDX-License-Identifier: LGPL-2.1-or-later */\n+/*\n+ * Copyright (C) 2019, Google Inc.\n+ *\n+ * camera_sensor.h - A camera sensor\n+ */\n+#ifndef __LIBCAMERA_CAMERA_SENSOR_H__\n+#define __LIBCAMERA_CAMERA_SENSOR_H__\n+\n+#include <string>\n+#include <vector>\n+\n+#include <libcamera/geometry.h>\n+\n+#include \"log.h\"\n+\n+namespace libcamera {\n+\n+class MediaEntity;\n+class V4L2Subdevice;\n+class V4L2SubdeviceFormat;\n+\n+class CameraSensor : protected Loggable\n+{\n+public:\n+\texplicit CameraSensor(const MediaEntity *entity);\n+\t~CameraSensor();\n+\n+\tCameraSensor(const CameraSensor &) = delete;\n+\tCameraSensor &operator=(const CameraSensor &) = delete;\n+\n+\tint init();\n+\n+\tconst MediaEntity *entity() const { return entity_; }\n+\tconst std::vector<unsigned int> &mbusCodes() const { return mbusCodes_; }\n+\tconst std::vector<Size> &sizes() const { return sizes_; }\n+\tconst Size &resolution() const;\n+\n+\tV4L2SubdeviceFormat getFormat(const std::vector<unsigned int> &mbusCodes,\n+\t\t\t\t const Size &size) const;\n+\tint setFormat(V4L2SubdeviceFormat *format);\n+\n+protected:\n+\tstd::string logPrefix() const;\n+\n+private:\n+\tconst MediaEntity *entity_;\n+\tV4L2Subdevice *subdev_;\n+\n+\tstd::vector<unsigned int> mbusCodes_;\n+\tstd::vector<Size> sizes_;\n+};\n+\n+} /* namespace libcamera */\n+\n+#endif /* __LIBCAMERA_CAMERA_SENSOR_H__ */\ndiff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\nindex cd36ac307518..cf4edec05755 100644\n--- a/src/libcamera/meson.build\n+++ b/src/libcamera/meson.build\n@@ -2,6 +2,7 @@ libcamera_sources = files([\n 'buffer.cpp',\n 'camera.cpp',\n 'camera_manager.cpp',\n+ 'camera_sensor.cpp',\n 'device_enumerator.cpp',\n 'event_dispatcher.cpp',\n 'event_dispatcher_poll.cpp',\n@@ -23,6 +24,7 @@ libcamera_sources = files([\n ])\n \n libcamera_headers = files([\n+ 'include/camera_sensor.h',\n 'include/device_enumerator.h',\n 'include/event_dispatcher_poll.h',\n 'include/formats.h',\n", "prefixes": [ "libcamera-devel", "v3", "11/13" ] }