[{"id":1454,"web_url":"https://patchwork.libcamera.org/comment/1454/","msgid":"<20190418144442.u6ue62b3rde4uxwn@uno.localdomain>","date":"2019-04-18T14:44:42","subject":"Re: [libcamera-devel] [PATCH v3 11/13] libcamera: camera_sensor:\n\tAdd a new class to model a camera sensor","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Laurent,\n\nOn Thu, Apr 18, 2019 at 05:14:35PM +0300, Laurent Pinchart wrote:\n> The CameraSensor class abstracts camera sensors and provides helper\n> functions to ease interactions with them. It is currently limited to\n> sensors that expose a single subdev, and offer the same frame sizes for\n> all media bus codes, but will be extended to support more complex\n> sensors as the needs arise.\n>\n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> ---\n> Changes 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\n>\n> diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp\n> new file mode 100644\n> index 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\nDon't we separate C++ and C includes?\n\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\nDebug or Error?\n\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\nSame. Were these intentional?\n\nMinors apart:\nReviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n\nThanks\n  j\n\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 */\n> diff --git a/src/libcamera/include/camera_sensor.h b/src/libcamera/include/camera_sensor.h\n> new file mode 100644\n> index 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__ */\n> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\n> index 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> --\n> Regards,\n>\n> Laurent Pinchart\n>\n> _______________________________________________\n> libcamera-devel mailing list\n> libcamera-devel@lists.libcamera.org\n> https://lists.libcamera.org/listinfo/libcamera-devel","headers":{"Return-Path":"<jacopo@jmondi.org>","Received":["from relay11.mail.gandi.net (relay11.mail.gandi.net\n\t[217.70.178.231])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 3EF6260DC6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 18 Apr 2019 16:43:51 +0200 (CEST)","from uno.localdomain (2-224-242-101.ip172.fastwebnet.it\n\t[2.224.242.101]) (Authenticated sender: jacopo@jmondi.org)\n\tby relay11.mail.gandi.net (Postfix) with ESMTPSA id 911EE100003;\n\tThu, 18 Apr 2019 14:43:50 +0000 (UTC)"],"Date":"Thu, 18 Apr 2019 16:44:42 +0200","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190418144442.u6ue62b3rde4uxwn@uno.localdomain>","References":"<20190418141437.14014-1-laurent.pinchart@ideasonboard.com>\n\t<20190418141437.14014-12-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"multipart/signed; micalg=pgp-sha256;\n\tprotocol=\"application/pgp-signature\"; boundary=\"l2lks2czq6dxx35r\"","Content-Disposition":"inline","In-Reply-To":"<20190418141437.14014-12-laurent.pinchart@ideasonboard.com>","User-Agent":"NeoMutt/20180716","Subject":"Re: [libcamera-devel] [PATCH v3 11/13] libcamera: camera_sensor:\n\tAdd a new 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:43:51 -0000"}},{"id":1456,"web_url":"https://patchwork.libcamera.org/comment/1456/","msgid":"<20190418150715.GS4806@pendragon.ideasonboard.com>","date":"2019-04-18T15:07:15","subject":"Re: [libcamera-devel] [PATCH v3 11/13] libcamera: camera_sensor:\n\tAdd a new class to model a camera sensor","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Jacopo,\n\nOn Thu, Apr 18, 2019 at 04:44:42PM +0200, Jacopo Mondi wrote:\n> On Thu, Apr 18, 2019 at 05:14:35PM +0300, Laurent Pinchart wrote:\n> > The CameraSensor class abstracts camera sensors and provides helper\n> > functions to ease interactions with them. It is currently limited to\n> > sensors that expose a single subdev, and offer the same frame sizes for\n> > all media bus codes, but will be extended to support more complex\n> > sensors as the needs arise.\n> >\n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> > ---\n> > Changes 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\n> >\n> > diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp\n> > new file mode 100644\n> > index 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> Don't we separate C++ and C includes?\n\nI've double-checked and we only do so in media_device.cpp and\nmedia_object.cpp, nowhere else.\n\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> \n> Debug or Error?\n> \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> \n> Same. Were these intentional?\n\nThey are, to let users of the CameraSensor class probe for supported\nformats without generating errors.\n\n> Minors apart:\n> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n> \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 */\n> > diff --git a/src/libcamera/include/camera_sensor.h b/src/libcamera/include/camera_sensor.h\n> > new file mode 100644\n> > index 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__ */\n> > diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\n> > index 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',","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 C5F9360DC6\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 18 Apr 2019 17:07:24 +0200 (CEST)","from pendragon.ideasonboard.com (81-175-216-236.bb.dnainternet.fi\n\t[81.175.216.236])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 2C617333;\n\tThu, 18 Apr 2019 17:07:24 +0200 (CEST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1555600044;\n\tbh=mXd1Z2UfcUKo4IBVEwBXKSkhdzKfRyr9Jmmit1lWf+E=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=iHIRU66IpblQz1bfcEjVwY34DSynfdVa4y8/Dyuh8VWx/ZnNHv/iJMDc82OJqdf4m\n\txO+msqV9BFeviKzygciPWbvhFzH3eu5SXHQVDsfaWDvXcF3OdrBO0lxx1ZcOx6V3PX\n\t1NhS+jJgtaaTs5+RU7NV97vWVHBZTsagCAaq09p8=","Date":"Thu, 18 Apr 2019 18:07:15 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190418150715.GS4806@pendragon.ideasonboard.com>","References":"<20190418141437.14014-1-laurent.pinchart@ideasonboard.com>\n\t<20190418141437.14014-12-laurent.pinchart@ideasonboard.com>\n\t<20190418144442.u6ue62b3rde4uxwn@uno.localdomain>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20190418144442.u6ue62b3rde4uxwn@uno.localdomain>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH v3 11/13] libcamera: camera_sensor:\n\tAdd a new 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 15:07:25 -0000"}},{"id":1460,"web_url":"https://patchwork.libcamera.org/comment/1460/","msgid":"<20190418152156.7eye2uwiixnjlky4@uno.localdomain>","date":"2019-04-18T15:21:56","subject":"Re: [libcamera-devel] [PATCH v3 11/13] libcamera: camera_sensor:\n\tAdd a new class to model a camera sensor","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Laurent,\n\nOn Thu, Apr 18, 2019 at 06:07:15PM +0300, Laurent Pinchart wrote:\n> Hi Jacopo,\n>\n> On Thu, Apr 18, 2019 at 04:44:42PM +0200, Jacopo Mondi wrote:\n> > On Thu, Apr 18, 2019 at 05:14:35PM +0300, Laurent Pinchart wrote:\n> > > The CameraSensor class abstracts camera sensors and provides helper\n> > > functions to ease interactions with them. It is currently limited to\n> > > sensors that expose a single subdev, and offer the same frame sizes for\n> > > all media bus codes, but will be extended to support more complex\n> > > sensors as the needs arise.\n> > >\n> > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > > Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> > > ---\n> > > Changes 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\n> > >\n> > > diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp\n> > > new file mode 100644\n> > > index 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> > Don't we separate C++ and C includes?\n>\n> I've double-checked and we only do so in media_device.cpp and\n> media_object.cpp, nowhere else.\n>\n\nAh, so it was just me!\nIt comes from here though:\nhttps://google.github.io/styleguide/cppguide.html#Names_and_Order_of_Includes\n\nbut let's fix those for consistency then\n\nThanks\n  j\n\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> >\n> > Debug or Error?\n> >\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> >\n> > Same. Were these intentional?\n>\n> They are, to let users of the CameraSensor class probe for supported\n> formats without generating errors.\n>\n> > Minors apart:\n> > Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n> >\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 */\n> > > diff --git a/src/libcamera/include/camera_sensor.h b/src/libcamera/include/camera_sensor.h\n> > > new file mode 100644\n> > > index 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__ */\n> > > diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\n> > > index 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>\n> --\n> Regards,\n>\n> Laurent Pinchart","headers":{"Return-Path":"<jacopo@jmondi.org>","Received":["from relay6-d.mail.gandi.net (relay6-d.mail.gandi.net\n\t[217.70.183.198])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 6162F60DBE\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 18 Apr 2019 17:21:04 +0200 (CEST)","from uno.localdomain (2-224-242-101.ip172.fastwebnet.it\n\t[2.224.242.101]) (Authenticated sender: jacopo@jmondi.org)\n\tby relay6-d.mail.gandi.net (Postfix) with ESMTPSA id CB37AC0006;\n\tThu, 18 Apr 2019 15:21:03 +0000 (UTC)"],"X-Originating-IP":"2.224.242.101","Date":"Thu, 18 Apr 2019 17:21:56 +0200","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190418152156.7eye2uwiixnjlky4@uno.localdomain>","References":"<20190418141437.14014-1-laurent.pinchart@ideasonboard.com>\n\t<20190418141437.14014-12-laurent.pinchart@ideasonboard.com>\n\t<20190418144442.u6ue62b3rde4uxwn@uno.localdomain>\n\t<20190418150715.GS4806@pendragon.ideasonboard.com>","MIME-Version":"1.0","Content-Type":"multipart/signed; micalg=pgp-sha256;\n\tprotocol=\"application/pgp-signature\"; boundary=\"qwftjudwufdurvz6\"","Content-Disposition":"inline","In-Reply-To":"<20190418150715.GS4806@pendragon.ideasonboard.com>","User-Agent":"NeoMutt/20180716","Subject":"Re: [libcamera-devel] [PATCH v3 11/13] libcamera: camera_sensor:\n\tAdd a new 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 15:21:04 -0000"}},{"id":1461,"web_url":"https://patchwork.libcamera.org/comment/1461/","msgid":"<20190418152702.GV4806@pendragon.ideasonboard.com>","date":"2019-04-18T15:27:02","subject":"Re: [libcamera-devel] [PATCH v3 11/13] libcamera: camera_sensor:\n\tAdd a new class to model a camera sensor","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Jacopo,\n\nOn Thu, Apr 18, 2019 at 05:21:56PM +0200, Jacopo Mondi wrote:\n> On Thu, Apr 18, 2019 at 06:07:15PM +0300, Laurent Pinchart wrote:\n> > On Thu, Apr 18, 2019 at 04:44:42PM +0200, Jacopo Mondi wrote:\n> >> On Thu, Apr 18, 2019 at 05:14:35PM +0300, Laurent Pinchart wrote:\n> >>> The CameraSensor class abstracts camera sensors and provides helper\n> >>> functions to ease interactions with them. It is currently limited to\n> >>> sensors that expose a single subdev, and offer the same frame sizes for\n> >>> all media bus codes, but will be extended to support more complex\n> >>> sensors as the needs arise.\n> >>>\n> >>> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> >>> Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n> >>> ---\n> >>> Changes 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\n> >>>\n> >>> diff --git a/src/libcamera/camera_sensor.cpp b/src/libcamera/camera_sensor.cpp\n> >>> new file mode 100644\n> >>> index 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> >> Don't we separate C++ and C includes?\n> >\n> > I've double-checked and we only do so in media_device.cpp and\n> > media_object.cpp, nowhere else.\n> \n> Ah, so it was just me!\n> It comes from here though:\n> https://google.github.io/styleguide/cppguide.html#Names_and_Order_of_Includes\n> \n> but let's fix those for consistency then\n\nI don't care too much about mixing the C and C++ headers or keeping them\nseparate. If you prefer to separate them, feel free to send a patch\n(note that there's no blank line between C and C++ headers in those C++\nguidelines). I however think it makes sense to include the .h\ncorresponding to the .cpp first, for the rationale explained in the\nguidelines. When it comes to headers from other libraries and from the\nproject (items 6 and 7) I would prefer a blank line between them.\n\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> >>\n> >> Debug or Error?\n> >>\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> >>\n> >> Same. Were these intentional?\n> >\n> > They are, to let users of the CameraSensor class probe for supported\n> > formats without generating errors.\n> >\n> >> Minors apart:\n> >> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>\n> >>\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 */\n> >>> diff --git a/src/libcamera/include/camera_sensor.h b/src/libcamera/include/camera_sensor.h\n> >>> new file mode 100644\n> >>> index 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__ */\n> >>> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build\n> >>> index 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',","headers":{"Return-Path":"<laurent.pinchart@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id D7AEF60DBE\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 18 Apr 2019 17:27:11 +0200 (CEST)","from pendragon.ideasonboard.com (81-175-216-236.bb.dnainternet.fi\n\t[81.175.216.236])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 1B86F333;\n\tThu, 18 Apr 2019 17:27:11 +0200 (CEST)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1555601231;\n\tbh=lO6mGBz+Z88LoMj27zaIt0JIbeD9Mwz+MAmhqGiY7Xo=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=G07BU5ZGJKHyNicrpiKT9ZiWm5gznNsxjRMsrg5de4whGRzHI2xwuZWdFmFFbpf+R\n\tCpoQ8IFKRiv6IFy7HrwyPBzF4lYPEnBhE0XUu2Mc3H+uNACamzdyFvUo1MNJ+iDvlf\n\t90Am7Mf8GR4ajkkWY5kIG2ULQlW2hK+9Qu0gwldg=","Date":"Thu, 18 Apr 2019 18:27:02 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Cc":"libcamera-devel@lists.libcamera.org","Message-ID":"<20190418152702.GV4806@pendragon.ideasonboard.com>","References":"<20190418141437.14014-1-laurent.pinchart@ideasonboard.com>\n\t<20190418141437.14014-12-laurent.pinchart@ideasonboard.com>\n\t<20190418144442.u6ue62b3rde4uxwn@uno.localdomain>\n\t<20190418150715.GS4806@pendragon.ideasonboard.com>\n\t<20190418152156.7eye2uwiixnjlky4@uno.localdomain>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<20190418152156.7eye2uwiixnjlky4@uno.localdomain>","User-Agent":"Mutt/1.10.1 (2018-07-13)","Subject":"Re: [libcamera-devel] [PATCH v3 11/13] libcamera: camera_sensor:\n\tAdd a new 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 15:27:12 -0000"}}]