<div dir="ltr"><div dir="ltr">Hi Jacopo, thank you for the patch.</div><div><br></div>I failed to apply the patch on the top of the latest tree to review.<div>Could you tell me the parent commit which I can apply this patch?</div><div><br></div><div>-Hiro<br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Jun 22, 2021 at 12:29 AM Jacopo Mondi <<a href="mailto:jacopo@jmondi.org">jacopo@jmondi.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">The camera_device.cpp has grown a little too much, and it has quickly<br>
become hard to maintain. Break out the handling of the static<br>
information collected at camera initialization time to a new<br>
CameraCapabilities class.<br>
<br>
Break out from the camera_device.cpp file all the functions relative to:<br>
- Initialization of supported stream configurations<br>
- Initialization of static metadata<br>
- Initialization of request templates<br>
<br>
Signed-off-by: Jacopo Mondi <<a href="mailto:jacopo@jmondi.org" target="_blank">jacopo@jmondi.org</a>><br>
Acked-by: Paul Elder <<a href="mailto:paul.elder@ideasonboard.com" target="_blank">paul.elder@ideasonboard.com</a>><br>
Tested-by: Paul Elder <<a href="mailto:paul.elder@ideasonboard.com" target="_blank">paul.elder@ideasonboard.com</a>><br>
---<br>
 src/android/camera_capabilities.cpp | 1164 +++++++++++++++++++++++++++<br>
 src/android/camera_capabilities.h  |  65 ++<br>
 src/android/camera_device.cpp    | 1147 +-------------------------<br>
 src/android/camera_device.h     |  27 +-<br>
 src/android/meson.build       |  1 +<br>
 5 files changed, 1245 insertions(+), 1159 deletions(-)<br>
 create mode 100644 src/android/camera_capabilities.cpp<br>
 create mode 100644 src/android/camera_capabilities.h<br>
<br>
diff --git a/src/android/camera_capabilities.cpp b/src/android/camera_capabilities.cpp<br>
new file mode 100644<br>
index 000000000000..311a2c839586<br>
--- /dev/null<br>
+++ b/src/android/camera_capabilities.cpp<br>
@@ -0,0 +1,1164 @@<br>
+/* SPDX-License-Identifier: LGPL-2.1-or-later */<br>
+/*<br>
+ * Copyright (C) 2021, Google Inc.<br>
+ *<br>
+ * camera_capabilities.cpp - Camera static properties manager<br>
+ */<br>
+<br>
+#include "camera_capabilities.h"<br>
+<br>
+#include <array><br>
+#include <cmath><br>
+<br>
+#include <hardware/camera3.h><br>
+<br>
+#include <libcamera/control_ids.h><br>
+#include <libcamera/controls.h><br>
+#include <libcamera/property_ids.h><br>
+<br>
+#include "libcamera/internal/formats.h"<br>
+#include "libcamera/internal/log.h"<br>
+<br>
+using namespace libcamera;<br>
+<br>
+LOG_DECLARE_CATEGORY(HAL)<br>
+<br>
+namespace {<br>
+<br>
+/*<br>
+ * \var camera3Resolutions<br>
+ * \brief The list of image resolutions defined as mandatory to be supported by<br>
+ * the Android Camera3 specification<br>
+ */<br>
+const std::vector<Size> camera3Resolutions = {<br>
+Â Â Â Â { 320, 240 },<br>
+Â Â Â Â { 640, 480 },<br>
+Â Â Â Â { 1280, 720 },<br>
+Â Â Â Â { 1920, 1080 }<br>
+};<br>
+<br>
+/*<br>
+ * \struct Camera3Format<br>
+ * \brief Data associated with an Android format identifier<br>
+ * \var libcameraFormats List of libcamera pixel formats compatible with the<br>
+ * Android format<br>
+ * \var name The human-readable representation of the Android format code<br>
+ */<br>
+struct Camera3Format {<br>
+Â Â Â Â std::vector<PixelFormat> libcameraFormats;<br>
+Â Â Â Â bool mandatory;<br>
+Â Â Â Â const char *name;<br>
+};<br>
+<br>
+/*<br>
+ * \var camera3FormatsMap<br>
+ * \brief Associate Android format code with ancillary data<br>
+ */<br>
+const std::map<int, const Camera3Format> camera3FormatsMap = {<br>
+Â Â Â Â {<br>
+Â Â Â Â Â Â Â Â HAL_PIXEL_FORMAT_BLOB, {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â { formats::MJPEG },<br>
+Â Â Â Â Â Â Â Â Â Â Â Â true,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â "BLOB"<br>
+Â Â Â Â Â Â Â Â }<br>
+Â Â Â Â }, {<br>
+Â Â Â Â Â Â Â Â HAL_PIXEL_FORMAT_YCbCr_420_888, {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â { formats::NV12, formats::NV21 },<br>
+Â Â Â Â Â Â Â Â Â Â Â Â true,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â "YCbCr_420_888"<br>
+Â Â Â Â Â Â Â Â }<br>
+Â Â Â Â }, {<br>
+Â Â Â Â Â Â Â Â /*<br>
+Â Â Â Â Â Â Â Â * \todo Translate IMPLEMENTATION_DEFINED inspecting the gralloc<br>
+Â Â Â Â Â Â Â Â * usage flag. For now, copy the YCbCr_420 configuration.<br>
+Â Â Â Â Â Â Â Â */<br>
+Â Â Â Â Â Â Â Â HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â { formats::NV12, formats::NV21 },<br>
+Â Â Â Â Â Â Â Â Â Â Â Â true,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â "IMPLEMENTATION_DEFINED"<br>
+Â Â Â Â Â Â Â Â }<br>
+Â Â Â Â }, {<br>
+Â Â Â Â Â Â Â Â HAL_PIXEL_FORMAT_RAW10, {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SBGGR10_CSI2P,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SGBRG10_CSI2P,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SGRBG10_CSI2P,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SRGGB10_CSI2P<br>
+Â Â Â Â Â Â Â Â Â Â Â Â },<br>
+Â Â Â Â Â Â Â Â Â Â Â Â false,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â "RAW10"<br>
+Â Â Â Â Â Â Â Â }<br>
+Â Â Â Â }, {<br>
+Â Â Â Â Â Â Â Â HAL_PIXEL_FORMAT_RAW12, {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SBGGR12_CSI2P,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SGBRG12_CSI2P,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SGRBG12_CSI2P,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SRGGB12_CSI2P<br>
+Â Â Â Â Â Â Â Â Â Â Â Â },<br>
+Â Â Â Â Â Â Â Â Â Â Â Â false,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â "RAW12"<br>
+Â Â Â Â Â Â Â Â }<br>
+Â Â Â Â }, {<br>
+Â Â Â Â Â Â Â Â HAL_PIXEL_FORMAT_RAW16, {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SBGGR16,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SGBRG16,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SGRBG16,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SRGGB16<br>
+Â Â Â Â Â Â Â Â Â Â Â Â },<br>
+Â Â Â Â Â Â Â Â Â Â Â Â false,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â "RAW16"<br>
+Â Â Â Â Â Â Â Â }<br>
+Â Â Â Â },<br>
+};<br>
+<br>
+} /* namespace */<br>
+<br>
+int CameraCapabilities::initialize(std::shared_ptr<libcamera::Camera> camera,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â int orientation, int facing)<br>
+{<br>
+Â Â Â Â camera_ = camera;<br>
+Â Â Â Â orientation_ = orientation;<br>
+Â Â Â Â facing_ = facing;<br>
+<br>
+Â Â Â Â /* Acquire the camera and initialize available stream configurations. */<br>
+Â Â Â Â int ret = camera_->acquire();<br>
+Â Â Â Â if (ret) {<br>
+Â Â Â Â Â Â Â Â LOG(HAL, Error) << "Failed to temporarily acquire the camera";<br>
+Â Â Â Â Â Â Â Â return ret;<br>
+Â Â Â Â }<br>
+<br>
+Â Â Â Â ret = initializeStreamConfigurations();<br>
+Â Â Â Â camera_->release();<br>
+Â Â Â Â if (ret)<br>
+Â Â Â Â Â Â Â Â return ret;<br>
+<br>
+Â Â Â Â return initializeStaticMetadata();<br>
+}<br>
+<br>
+std::vector<Size> CameraCapabilities::getYUVResolutions(CameraConfiguration *cameraConfig,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â const PixelFormat &pixelFormat,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â const std::vector<Size> &resolutions)<br>
+{<br>
+Â Â Â Â std::vector<Size> supportedResolutions;<br>
+<br>
+Â Â Â Â StreamConfiguration &cfg = cameraConfig->at(0);<br>
+Â Â Â Â for (const Size &res : resolutions) {<br>
+Â Â Â Â Â Â Â Â cfg.pixelFormat = pixelFormat;<br>
+Â Â Â Â Â Â Â Â cfg.size = res;<br>
+<br>
+Â Â Â Â Â Â Â Â CameraConfiguration::Status status = cameraConfig->validate();<br>
+Â Â Â Â Â Â Â Â if (status != CameraConfiguration::Valid) {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â LOG(HAL, Debug) << cfg.toString() << " not supported";<br>
+Â Â Â Â Â Â Â Â Â Â Â Â continue;<br>
+Â Â Â Â Â Â Â Â }<br>
+<br>
+Â Â Â Â Â Â Â Â LOG(HAL, Debug) << cfg.toString() << " supported";<br>
+<br>
+Â Â Â Â Â Â Â Â supportedResolutions.push_back(res);<br>
+Â Â Â Â }<br>
+<br>
+Â Â Â Â return supportedResolutions;<br>
+}<br>
+<br>
+std::vector<Size> CameraCapabilities::getRawResolutions(const libcamera::PixelFormat &pixelFormat)<br>
+{<br>
+Â Â Â Â std::unique_ptr<CameraConfiguration> cameraConfig =<br>
+Â Â Â Â Â Â Â Â camera_->generateConfiguration({ StreamRole::Raw });<br>
+Â Â Â Â StreamConfiguration &cfg = cameraConfig->at(0);<br>
+Â Â Â Â const StreamFormats &formats = cfg.formats();<br>
+Â Â Â Â std::vector<Size> supportedResolutions = formats.sizes(pixelFormat);<br>
+<br>
+Â Â Â Â return supportedResolutions;<br>
+}<br>
+<br>
+/*<br>
+ * Initialize the format conversion map to translate from Android format<br>
+ * identifier to libcamera pixel formats and fill in the list of supported<br>
+ * stream configurations to be reported to the Android camera framework through<br>
+ * the Camera static metadata.<br>
+ */<br>
+int CameraCapabilities::initializeStreamConfigurations()<br>
+{<br>
+Â Â Â Â /*<br>
+Â Â Â Â * Get the maximum output resolutions<br>
+Â Â Â Â * \todo Get this from the camera properties once defined<br>
+Â Â Â Â */<br>
+Â Â Â Â std::unique_ptr<CameraConfiguration> cameraConfig =<br>
+Â Â Â Â Â Â Â Â camera_->generateConfiguration({ StillCapture });<br>
+Â Â Â Â if (!cameraConfig) {<br>
+Â Â Â Â Â Â Â Â LOG(HAL, Error) << "Failed to get maximum resolution";<br>
+Â Â Â Â Â Â Â Â return -EINVAL;<br>
+Â Â Â Â }<br>
+Â Â Â Â StreamConfiguration &cfg = cameraConfig->at(0);<br>
+<br>
+Â Â Â Â /*<br>
+Â Â Â Â * \todo JPEG - Adjust the maximum available resolution by taking the<br>
+Â Â Â Â * JPEG encoder requirements into account (alignment and aspect ratio).<br>
+Â Â Â Â */<br>
+Â Â Â Â const Size maxRes = cfg.size;<br>
+Â Â Â Â LOG(HAL, Debug) << "Maximum supported resolution: " << maxRes.toString();<br>
+<br>
+Â Â Â Â /*<br>
+Â Â Â Â * Build the list of supported image resolutions.<br>
+Â Â Â Â *<br>
+Â Â Â Â * The resolutions listed in camera3Resolution are mandatory to be<br>
+Â Â Â Â * supported, up to the camera maximum resolution.<br>
+Â Â Â Â *<br>
+Â Â Â Â * Augment the list by adding resolutions calculated from the camera<br>
+Â Â Â Â * maximum one.<br>
+Â Â Â Â */<br>
+Â Â Â Â std::vector<Size> cameraResolutions;<br>
+Â Â Â Â std::copy_if(camera3Resolutions.begin(), camera3Resolutions.end(),<br>
+Â Â Â Â Â Â Â Â Â Â std::back_inserter(cameraResolutions),<br>
+Â Â Â Â Â Â Â Â Â Â [&](const Size &res) { return res < maxRes; });<br>
+<br>
+Â Â Â Â /*<br>
+Â Â Â Â * The Camera3 specification suggests adding 1/2 and 1/4 of the maximum<br>
+Â Â Â Â * resolution.<br>
+Â Â Â Â */<br>
+Â Â Â Â for (unsigned int divider = 2;; divider <<= 1) {<br>
+Â Â Â Â Â Â Â Â Size derivedSize{<br>
+Â Â Â Â Â Â Â Â Â Â Â Â maxRes.width / divider,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â maxRes.height / divider,<br>
+Â Â Â Â Â Â Â Â };<br>
+<br>
+Â Â Â Â Â Â Â Â if (derivedSize.width < 320 ||<br>
+Â Â Â Â Â Â Â Â Â Â derivedSize.height < 240)<br>
+Â Â Â Â Â Â Â Â Â Â Â Â break;<br>
+<br>
+Â Â Â Â Â Â Â Â cameraResolutions.push_back(derivedSize);<br>
+Â Â Â Â }<br>
+Â Â Â Â cameraResolutions.push_back(maxRes);<br>
+<br>
+Â Â Â Â /* Remove duplicated entries from the list of supported resolutions. */<br>
+Â Â Â Â std::sort(cameraResolutions.begin(), cameraResolutions.end());<br>
+Â Â Â Â auto last = std::unique(cameraResolutions.begin(), cameraResolutions.end());<br>
+Â Â Â Â cameraResolutions.erase(last, cameraResolutions.end());<br>
+<br>
+Â Â Â Â /*<br>
+Â Â Â Â * Build the list of supported camera formats.<br>
+Â Â Â Â *<br>
+Â Â Â Â * To each Android format a list of compatible libcamera formats is<br>
+Â Â Â Â * associated. The first libcamera format that tests successful is added<br>
+Â Â Â Â * to the format translation map used when configuring the streams.<br>
+Â Â Â Â * It is then tested against the list of supported camera resolutions to<br>
+Â Â Â Â * build the stream configuration map reported through the camera static<br>
+Â Â Â Â * metadata.<br>
+Â Â Â Â */<br>
+Â Â Â Â Size maxJpegSize;<br>
+Â Â Â Â for (const auto &format : camera3FormatsMap) {<br>
+Â Â Â Â Â Â Â Â int androidFormat = format.first;<br>
+Â Â Â Â Â Â Â Â const Camera3Format &camera3Format = format.second;<br>
+Â Â Â Â Â Â Â Â const std::vector<PixelFormat> &libcameraFormats =<br>
+Â Â Â Â Â Â Â Â Â Â Â Â camera3Format.libcameraFormats;<br>
+<br>
+Â Â Â Â Â Â Â Â LOG(HAL, Debug) << "Trying to map Android format "<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << camera3Format.name;<br>
+<br>
+Â Â Â Â Â Â Â Â /*<br>
+Â Â Â Â Â Â Â Â * JPEG is always supported, either produced directly by the<br>
+Â Â Â Â Â Â Â Â * camera, or encoded in the HAL.<br>
+Â Â Â Â Â Â Â Â */<br>
+Â Â Â Â Â Â Â Â if (androidFormat == HAL_PIXEL_FORMAT_BLOB) {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â formatsMap_[androidFormat] = formats::MJPEG;<br>
+Â Â Â Â Â Â Â Â Â Â Â Â LOG(HAL, Debug) << "Mapped Android format "<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << camera3Format.name << " to "<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << formats::MJPEG.toString()<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << " (fixed mapping)";<br>
+Â Â Â Â Â Â Â Â Â Â Â Â continue;<br>
+Â Â Â Â Â Â Â Â }<br>
+<br>
+Â Â Â Â Â Â Â Â /*<br>
+Â Â Â Â Â Â Â Â * Test the libcamera formats that can produce images<br>
+Â Â Â Â Â Â Â Â * compatible with the format defined by Android.<br>
+Â Â Â Â Â Â Â Â */<br>
+Â Â Â Â Â Â Â Â PixelFormat mappedFormat;<br>
+Â Â Â Â Â Â Â Â for (const PixelFormat &pixelFormat : libcameraFormats) {<br>
+<br>
+Â Â Â Â Â Â Â Â Â Â Â Â LOG(HAL, Debug) << "Testing " << pixelFormat.toString();<br>
+<br>
+Â Â Â Â Â Â Â Â Â Â Â Â /*<br>
+Â Â Â Â Â Â Â Â Â Â Â Â * The stream configuration size can be adjusted,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â * not the pixel format.<br>
+Â Â Â Â Â Â Â Â Â Â Â Â *<br>
+Â Â Â Â Â Â Â Â Â Â Â Â * \todo This could be simplified once all pipeline<br>
+Â Â Â Â Â Â Â Â Â Â Â Â * handlers will report the StreamFormats list of<br>
+Â Â Â Â Â Â Â Â Â Â Â Â * supported formats.<br>
+Â Â Â Â Â Â Â Â Â Â Â Â */<br>
+Â Â Â Â Â Â Â Â Â Â Â Â cfg.pixelFormat = pixelFormat;<br>
+<br>
+Â Â Â Â Â Â Â Â Â Â Â Â CameraConfiguration::Status status = cameraConfig->validate();<br>
+Â Â Â Â Â Â Â Â Â Â Â Â if (status != CameraConfiguration::Invalid &&<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â cfg.pixelFormat == pixelFormat) {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â mappedFormat = pixelFormat;<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;<br>
+Â Â Â Â Â Â Â Â Â Â Â Â }<br>
+Â Â Â Â Â Â Â Â }<br>
+<br>
+Â Â Â Â Â Â Â Â if (!mappedFormat.isValid()) {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â /* If the format is not mandatory, skip it. */<br>
+Â Â Â Â Â Â Â Â Â Â Â Â if (!camera3Format.mandatory)<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â continue;<br>
+<br>
+Â Â Â Â Â Â Â Â Â Â Â Â LOG(HAL, Error)<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << "Failed to map mandatory Android format "<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << camera3Format.name << " ("<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << utils::hex(androidFormat) << "): aborting";<br>
+Â Â Â Â Â Â Â Â Â Â Â Â return -EINVAL;<br>
+Â Â Â Â Â Â Â Â }<br>
+<br>
+Â Â Â Â Â Â Â Â /*<br>
+Â Â Â Â Â Â Â Â * Record the mapping and then proceed to generate the<br>
+Â Â Â Â Â Â Â Â * stream configurations map, by testing the image resolutions.<br>
+Â Â Â Â Â Â Â Â */<br>
+Â Â Â Â Â Â Â Â formatsMap_[androidFormat] = mappedFormat;<br>
+Â Â Â Â Â Â Â Â LOG(HAL, Debug) << "Mapped Android format "<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << camera3Format.name << " to "<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << mappedFormat.toString();<br>
+<br>
+Â Â Â Â Â Â Â Â std::vector<Size> resolutions;<br>
+Â Â Â Â Â Â Â Â const PixelFormatInfo &info = PixelFormatInfo::info(mappedFormat);<br>
+Â Â Â Â Â Â Â Â if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW)<br>
+Â Â Â Â Â Â Â Â Â Â Â Â resolutions = getRawResolutions(mappedFormat);<br>
+Â Â Â Â Â Â Â Â else<br>
+Â Â Â Â Â Â Â Â Â Â Â Â resolutions = getYUVResolutions(cameraConfig.get(),<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â mappedFormat,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â cameraResolutions);<br>
+<br>
+Â Â Â Â Â Â Â Â for (const Size &res : resolutions) {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â streamConfigurations_.push_back({ res, androidFormat });<br>
+<br>
+Â Â Â Â Â Â Â Â Â Â Â Â /*<br>
+Â Â Â Â Â Â Â Â Â Â Â Â * If the format is HAL_PIXEL_FORMAT_YCbCr_420_888<br>
+Â Â Â Â Â Â Â Â Â Â Â Â * from which JPEG is produced, add an entry for<br>
+Â Â Â Â Â Â Â Â Â Â Â Â * the JPEG stream.<br>
+Â Â Â Â Â Â Â Â Â Â Â Â *<br>
+Â Â Â Â Â Â Â Â Â Â Â Â * \todo Wire the JPEG encoder to query the supported<br>
+Â Â Â Â Â Â Â Â Â Â Â Â * sizes provided a list of formats it can encode.<br>
+Â Â Â Â Â Â Â Â Â Â Â Â *<br>
+Â Â Â Â Â Â Â Â Â Â Â Â * \todo Support JPEG streams produced by the Camera<br>
+Â Â Â Â Â Â Â Â Â Â Â Â * natively.<br>
+Â Â Â Â Â Â Â Â Â Â Â Â */<br>
+Â Â Â Â Â Â Â Â Â Â Â Â if (androidFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â streamConfigurations_.push_back(<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â { res, HAL_PIXEL_FORMAT_BLOB });<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â maxJpegSize = std::max(maxJpegSize, res);<br>
+Â Â Â Â Â Â Â Â Â Â Â Â }<br>
+Â Â Â Â Â Â Â Â }<br>
+<br>
+Â Â Â Â Â Â Â Â /*<br>
+Â Â Â Â Â Â Â Â * \todo Calculate the maximum JPEG buffer size by asking the<br>
+Â Â Â Â Â Â Â Â * encoder giving the maximum frame size required.<br>
+Â Â Â Â Â Â Â Â */<br>
+Â Â Â Â Â Â Â Â maxJpegBufferSize_ = maxJpegSize.width * maxJpegSize.height * 1.5;<br>
+Â Â Â Â }<br>
+<br>
+Â Â Â Â LOG(HAL, Debug) << "Collected stream configuration map: ";<br>
+Â Â Â Â for (const auto &entry : streamConfigurations_)<br>
+Â Â Â Â Â Â Â Â LOG(HAL, Debug) << "{ " << entry.resolution.toString() << " - "<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << utils::hex(entry.androidFormat) << " }";<br>
+<br>
+Â Â Â Â return 0;<br>
+}<br>
+<br>
+int CameraCapabilities::initializeStaticMetadata()<br>
+{<br>
+Â Â Â Â staticMetadata_ = std::make_unique<CameraMetadata>(64, 1024);<br>
+Â Â Â Â if (!staticMetadata_->isValid()) {<br>
+Â Â Â Â Â Â Â Â LOG(HAL, Error) << "Failed to allocate static metadata";<br>
+Â Â Â Â Â Â Â Â staticMetadata_.reset();<br>
+Â Â Â Â Â Â Â Â return -EINVAL;<br>
+Â Â Â Â }<br>
+<br>
+Â Â Â Â const ControlInfoMap &controlsInfo = camera_->controls();<br>
+Â Â Â Â const ControlList &properties = camera_->properties();<br>
+<br>
+Â Â Â Â /* Color correction static metadata. */<br>
+Â Â Â Â {<br>
+Â Â Â Â Â Â Â Â std::vector<uint8_t> data;<br>
+Â Â Â Â Â Â Â Â data.reserve(3);<br>
+Â Â Â Â Â Â Â Â const auto &infoMap = controlsInfo.find(&controls::draft::ColorCorrectionAberrationMode);<br>
+Â Â Â Â Â Â Â Â if (infoMap != controlsInfo.end()) {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â for (const auto &value : infoMap->second.values())<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â data.push_back(value.get<int32_t>());<br>
+Â Â Â Â Â Â Â Â } else {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â data.push_back(ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF);<br>
+Â Â Â Â Â Â Â Â }<br>
+Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â data);<br>
+Â Â Â Â }<br>
+<br>
+Â Â Â Â /* Control static metadata. */<br>
+Â Â Â Â std::vector<uint8_t> aeAvailableAntiBandingModes = {<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO,<br>
+Â Â Â Â };<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â aeAvailableAntiBandingModes);<br>
+<br>
+Â Â Â Â std::vector<uint8_t> aeAvailableModes = {<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_MODE_ON,<br>
+Â Â Â Â };<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_MODES,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â aeAvailableModes);<br>
+<br>
+Â Â Â Â int64_t minFrameDurationNsec = -1;<br>
+Â Â Â Â int64_t maxFrameDurationNsec = -1;<br>
+Â Â Â Â const auto frameDurationsInfo = controlsInfo.find(&controls::FrameDurationLimits);<br>
+Â Â Â Â if (frameDurationsInfo != controlsInfo.end()) {<br>
+Â Â Â Â Â Â Â Â minFrameDurationNsec = frameDurationsInfo->second.min().get<int64_t>() * 1000;<br>
+Â Â Â Â Â Â Â Â maxFrameDurationNsec = frameDurationsInfo->second.max().get<int64_t>() * 1000;<br>
+<br>
+Â Â Â Â Â Â Â Â /*<br>
+Â Â Â Â Â Â Â Â * Adjust the minimum frame duration to comply with Android<br>
+Â Â Â Â Â Â Â Â * requirements. The camera service mandates all preview/record<br>
+Â Â Â Â Â Â Â Â * streams to have a minimum frame duration < 33,366 milliseconds<br>
+Â Â Â Â Â Â Â Â * (see MAX_PREVIEW_RECORD_DURATION_NS in the camera service<br>
+Â Â Â Â Â Â Â Â * implementation).<br>
+Â Â Â Â Â Â Â Â *<br>
+Â Â Â Â Â Â Â Â * If we're close enough (+ 500 useconds) to that value, round<br>
+Â Â Â Â Â Â Â Â * the minimum frame duration of the camera to an accepted<br>
+Â Â Â Â Â Â Â Â * value.<br>
+Â Â Â Â Â Â Â Â */<br>
+Â Â Â Â Â Â Â Â static constexpr int64_t MAX_PREVIEW_RECORD_DURATION_NS = 1e9 / 29.97;<br>
+Â Â Â Â Â Â Â Â if (minFrameDurationNsec > MAX_PREVIEW_RECORD_DURATION_NS &&<br>
+Â Â Â Â Â Â Â Â Â Â minFrameDurationNsec < MAX_PREVIEW_RECORD_DURATION_NS + 500000)<br>
+Â Â Â Â Â Â Â Â Â Â Â Â minFrameDurationNsec = MAX_PREVIEW_RECORD_DURATION_NS - 1000;<br>
+<br>
+Â Â Â Â Â Â Â Â /*<br>
+Â Â Â Â Â Â Â Â * The AE routine frame rate limits are computed using the frame<br>
+Â Â Â Â Â Â Â Â * duration limits, as libcamera clips the AE routine to the<br>
+Â Â Â Â Â Â Â Â * frame durations.<br>
+Â Â Â Â Â Â Â Â */<br>
+Â Â Â Â Â Â Â Â int32_t maxFps = std::round(1e9 / minFrameDurationNsec);<br>
+Â Â Â Â Â Â Â Â int32_t minFps = std::round(1e9 / maxFrameDurationNsec);<br>
+Â Â Â Â Â Â Â Â minFps = std::max(1, minFps);<br>
+<br>
+Â Â Â Â Â Â Â Â /*<br>
+Â Â Â Â Â Â Â Â * Force rounding errors so that we have the proper frame<br>
+Â Â Â Â Â Â Â Â * durations for when we reuse these variables later<br>
+Â Â Â Â Â Â Â Â */<br>
+Â Â Â Â Â Â Â Â minFrameDurationNsec = 1e9 / maxFps;<br>
+Â Â Â Â Â Â Â Â maxFrameDurationNsec = 1e9 / minFps;<br>
+<br>
+Â Â Â Â Â Â Â Â /*<br>
+Â Â Â Â Â Â Â Â * Register to the camera service {min, max} and {max, max}<br>
+Â Â Â Â Â Â Â Â * intervals as requested by the metadata documentation.<br>
+Â Â Â Â Â Â Â Â */<br>
+Â Â Â Â Â Â Â Â int32_t availableAeFpsTarget[] = {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â minFps, maxFps, maxFps, maxFps<br>
+Â Â Â Â Â Â Â Â };<br>
+Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableAeFpsTarget);<br>
+Â Â Â Â }<br>
+<br>
+Â Â Â Â std::vector<int32_t> aeCompensationRange = {<br>
+Â Â Â Â Â Â Â Â 0, 0,<br>
+Â Â Â Â };<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_RANGE,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â aeCompensationRange);<br>
+<br>
+Â Â Â Â const camera_metadata_rational_t aeCompensationStep[] = {<br>
+Â Â Â Â Â Â Â Â { 0, 1 }<br>
+Â Â Â Â };<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_STEP,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â aeCompensationStep);<br>
+<br>
+Â Â Â Â std::vector<uint8_t> availableAfModes = {<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AF_MODE_OFF,<br>
+Â Â Â Â };<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AF_AVAILABLE_MODES,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableAfModes);<br>
+<br>
+Â Â Â Â std::vector<uint8_t> availableEffects = {<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_EFFECT_MODE_OFF,<br>
+Â Â Â Â };<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_EFFECTS,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableEffects);<br>
+<br>
+Â Â Â Â std::vector<uint8_t> availableSceneModes = {<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_SCENE_MODE_DISABLED,<br>
+Â Â Â Â };<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_SCENE_MODES,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableSceneModes);<br>
+<br>
+Â Â Â Â std::vector<uint8_t> availableStabilizationModes = {<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF,<br>
+Â Â Â Â };<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableStabilizationModes);<br>
+<br>
+Â Â Â Â /*<br>
+Â Â Â Â * \todo Inspect the Camera capabilities to report the available<br>
+Â Â Â Â * AWB modes. Default to AUTO as CTS tests require it.<br>
+Â Â Â Â */<br>
+Â Â Â Â std::vector<uint8_t> availableAwbModes = {<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AWB_MODE_AUTO,<br>
+Â Â Â Â };<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AWB_AVAILABLE_MODES,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableAwbModes);<br>
+<br>
+Â Â Â Â std::vector<int32_t> availableMaxRegions = {<br>
+Â Â Â Â Â Â Â Â 0, 0, 0,<br>
+Â Â Â Â };<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_MAX_REGIONS,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableMaxRegions);<br>
+<br>
+Â Â Â Â std::vector<uint8_t> sceneModesOverride = {<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_MODE_ON,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AWB_MODE_AUTO,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AF_MODE_OFF,<br>
+Â Â Â Â };<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_SCENE_MODE_OVERRIDES,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sceneModesOverride);<br>
+<br>
+Â Â Â Â uint8_t aeLockAvailable = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE;<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â aeLockAvailable);<br>
+<br>
+Â Â Â Â uint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AWB_LOCK_AVAILABLE,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â awbLockAvailable);<br>
+<br>
+Â Â Â Â char availableControlModes = ANDROID_CONTROL_MODE_AUTO;<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_MODES,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableControlModes);<br>
+<br>
+Â Â Â Â /* JPEG static metadata. */<br>
+<br>
+Â Â Â Â /*<br>
+Â Â Â Â * Create the list of supported thumbnail sizes by inspecting the<br>
+Â Â Â Â * available JPEG resolutions collected in streamConfigurations_ and<br>
+Â Â Â Â * generate one entry for each aspect ratio.<br>
+Â Â Â Â *<br>
+Â Â Â Â * The JPEG thumbnailer can freely scale, so pick an arbitrary<br>
+Â Â Â Â * (160, 160) size as the bounding rectangle, which is then cropped to<br>
+Â Â Â Â * the different supported aspect ratios.<br>
+Â Â Â Â */<br>
+Â Â Â Â constexpr Size maxJpegThumbnail(160, 160);<br>
+Â Â Â Â std::vector<Size> thumbnailSizes;<br>
+Â Â Â Â thumbnailSizes.push_back({ 0, 0 });<br>
+Â Â Â Â for (const auto &entry : streamConfigurations_) {<br>
+Â Â Â Â Â Â Â Â if (entry.androidFormat != HAL_PIXEL_FORMAT_BLOB)<br>
+Â Â Â Â Â Â Â Â Â Â Â Â continue;<br>
+<br>
+Â Â Â Â Â Â Â Â Size thumbnailSize = maxJpegThumbnail<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â .boundedToAspectRatio({ entry.resolution.width,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â entry.resolution.height });<br>
+Â Â Â Â Â Â Â Â thumbnailSizes.push_back(thumbnailSize);<br>
+Â Â Â Â }<br>
+<br>
+Â Â Â Â std::sort(thumbnailSizes.begin(), thumbnailSizes.end());<br>
+Â Â Â Â auto last = std::unique(thumbnailSizes.begin(), thumbnailSizes.end());<br>
+Â Â Â Â thumbnailSizes.erase(last, thumbnailSizes.end());<br>
+<br>
+Â Â Â Â /* Transform sizes in to a list of integers that can be consumed. */<br>
+Â Â Â Â std::vector<int32_t> thumbnailEntries;<br>
+Â Â Â Â thumbnailEntries.reserve(thumbnailSizes.size() * 2);<br>
+Â Â Â Â for (const auto &size : thumbnailSizes) {<br>
+Â Â Â Â Â Â Â Â thumbnailEntries.push_back(size.width);<br>
+Â Â Â Â Â Â Â Â thumbnailEntries.push_back(size.height);<br>
+Â Â Â Â }<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â thumbnailEntries);<br>
+<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_JPEG_MAX_SIZE, maxJpegBufferSize_);<br>
+<br>
+Â Â Â Â /* Sensor static metadata. */<br>
+Â Â Â Â std::array<int32_t, 2> pixelArraySize;<br>
+Â Â Â Â {<br>
+Â Â Â Â Â Â Â Â const Size &size = properties.get(properties::PixelArraySize);<br>
+Â Â Â Â Â Â Â Â pixelArraySize[0] = size.width;<br>
+Â Â Â Â Â Â Â Â pixelArraySize[1] = size.height;<br>
+Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â pixelArraySize);<br>
+Â Â Â Â }<br>
+<br>
+Â Â Â Â if (properties.contains(properties::UnitCellSize)) {<br>
+Â Â Â Â Â Â Â Â const Size &cellSize = properties.get<Size>(properties::UnitCellSize);<br>
+Â Â Â Â Â Â Â Â std::array<float, 2> physicalSize{<br>
+Â Â Â Â Â Â Â Â Â Â Â Â cellSize.width * pixelArraySize[0] / 1e6f,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â cellSize.height * pixelArraySize[1] / 1e6f<br>
+Â Â Â Â Â Â Â Â };<br>
+Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â physicalSize);<br>
+Â Â Â Â }<br>
+<br>
+Â Â Â Â {<br>
+Â Â Â Â Â Â Â Â const Span<const Rectangle> &rects =<br>
+Â Â Â Â Â Â Â Â Â Â Â Â properties.get(properties::PixelArrayActiveAreas);<br>
+Â Â Â Â Â Â Â Â std::vector<int32_t> data{<br>
+Â Â Â Â Â Â Â Â Â Â Â Â static_cast<int32_t>(rects[0].x),<br>
+Â Â Â Â Â Â Â Â Â Â Â Â static_cast<int32_t>(rects[0].y),<br>
+Â Â Â Â Â Â Â Â Â Â Â Â static_cast<int32_t>(rects[0].width),<br>
+Â Â Â Â Â Â Â Â Â Â Â Â static_cast<int32_t>(rects[0].height),<br>
+Â Â Â Â Â Â Â Â };<br>
+Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â data);<br>
+Â Â Â Â }<br>
+<br>
+Â Â Â Â int32_t sensitivityRange[] = {<br>
+Â Â Â Â Â Â Â Â 32, 2400,<br>
+Â Â Â Â };<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sensitivityRange);<br>
+<br>
+Â Â Â Â /* Report the color filter arrangement if the camera reports it. */<br>
+Â Â Â Â if (properties.contains(properties::draft::ColorFilterArrangement)) {<br>
+Â Â Â Â Â Â Â Â uint8_t filterArr = properties.get(properties::draft::ColorFilterArrangement);<br>
+Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â filterArr);<br>
+Â Â Â Â }<br>
+<br>
+Â Â Â Â const auto &exposureInfo = controlsInfo.find(&controls::ExposureTime);<br>
+Â Â Â Â if (exposureInfo != controlsInfo.end()) {<br>
+Â Â Â Â Â Â Â Â int64_t exposureTimeRange[2] = {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â exposureInfo->second.min().get<int32_t>() * 1000LL,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â exposureInfo->second.max().get<int32_t>() * 1000LL,<br>
+Â Â Â Â Â Â Â Â };<br>
+Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â exposureTimeRange, 2);<br>
+Â Â Â Â }<br>
+<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_SENSOR_ORIENTATION, orientation_);<br>
+<br>
+Â Â Â Â std::vector<int32_t> testPatternModes = {<br>
+Â Â Â Â Â Â Â Â ANDROID_SENSOR_TEST_PATTERN_MODE_OFF<br>
+Â Â Â Â };<br>
+Â Â Â Â const auto &testPatternsInfo =<br>
+Â Â Â Â Â Â Â Â controlsInfo.find(&controls::draft::TestPatternMode);<br>
+Â Â Â Â if (testPatternsInfo != controlsInfo.end()) {<br>
+Â Â Â Â Â Â Â Â const auto &values = testPatternsInfo->second.values();<br>
+Â Â Â Â Â Â Â Â ASSERT(!values.empty());<br>
+Â Â Â Â Â Â Â Â for (const auto &value : values) {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â switch (value.get<int32_t>()) {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â case controls::draft::TestPatternModeOff:<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â /*<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â * ANDROID_SENSOR_TEST_PATTERN_MODE_OFF is<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â * already in testPatternModes.<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â */<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;<br>
+<br>
+Â Â Â Â Â Â Â Â Â Â Â Â case controls::draft::TestPatternModeSolidColor:<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â testPatternModes.push_back(<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR);<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;<br>
+<br>
+Â Â Â Â Â Â Â Â Â Â Â Â case controls::draft::TestPatternModeColorBars:<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â testPatternModes.push_back(<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS);<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;<br>
+<br>
+Â Â Â Â Â Â Â Â Â Â Â Â case controls::draft::TestPatternModeColorBarsFadeToGray:<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â testPatternModes.push_back(<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY);<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;<br>
+<br>
+Â Â Â Â Â Â Â Â Â Â Â Â case controls::draft::TestPatternModePn9:<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â testPatternModes.push_back(<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ANDROID_SENSOR_TEST_PATTERN_MODE_PN9);<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;<br>
+<br>
+Â Â Â Â Â Â Â Â Â Â Â Â case controls::draft::TestPatternModeCustom1:<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â /* We don't support this yet. */<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;<br>
+<br>
+Â Â Â Â Â Â Â Â Â Â Â Â default:<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â LOG(HAL, Error) << "Unknown test pattern mode: "<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << value.get<int32_t>();<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â continue;<br>
+Â Â Â Â Â Â Â Â Â Â Â Â }<br>
+Â Â Â Â Â Â Â Â }<br>
+Â Â Â Â }<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â testPatternModes);<br>
+<br>
+Â Â Â Â uint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â timestampSource);<br>
+<br>
+Â Â Â Â if (maxFrameDurationNsec > 0)<br>
+Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â maxFrameDurationNsec);<br>
+<br>
+Â Â Â Â /* Statistics static metadata. */<br>
+Â Â Â Â uint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â faceDetectMode);<br>
+<br>
+Â Â Â Â int32_t maxFaceCount = 0;<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â maxFaceCount);<br>
+<br>
+Â Â Â Â {<br>
+Â Â Â Â Â Â Â Â std::vector<uint8_t> data;<br>
+Â Â Â Â Â Â Â Â data.reserve(2);<br>
+Â Â Â Â Â Â Â Â const auto &infoMap = controlsInfo.find(&controls::draft::LensShadingMapMode);<br>
+Â Â Â Â Â Â Â Â if (infoMap != controlsInfo.end()) {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â for (const auto &value : infoMap->second.values())<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â data.push_back(value.get<int32_t>());<br>
+Â Â Â Â Â Â Â Â } else {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â data.push_back(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF);<br>
+Â Â Â Â Â Â Â Â }<br>
+Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â data);<br>
+Â Â Â Â }<br>
+<br>
+Â Â Â Â /* Sync static metadata. */<br>
+Â Â Â Â int32_t maxLatency = ANDROID_SYNC_MAX_LATENCY_UNKNOWN;<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_SYNC_MAX_LATENCY, maxLatency);<br>
+<br>
+Â Â Â Â /* Flash static metadata. */<br>
+Â Â Â Â char flashAvailable = ANDROID_FLASH_INFO_AVAILABLE_FALSE;<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_FLASH_INFO_AVAILABLE,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â flashAvailable);<br>
+<br>
+Â Â Â Â /* Lens static metadata. */<br>
+Â Â Â Â std::vector<float> lensApertures = {<br>
+Â Â Â Â Â Â Â Â 2.53 / 100,<br>
+Â Â Â Â };<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_APERTURES,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â lensApertures);<br>
+<br>
+Â Â Â Â uint8_t lensFacing;<br>
+Â Â Â Â switch (facing_) {<br>
+Â Â Â Â default:<br>
+Â Â Â Â case CAMERA_FACING_FRONT:<br>
+Â Â Â Â Â Â Â Â lensFacing = ANDROID_LENS_FACING_FRONT;<br>
+Â Â Â Â Â Â Â Â break;<br>
+Â Â Â Â case CAMERA_FACING_BACK:<br>
+Â Â Â Â Â Â Â Â lensFacing = ANDROID_LENS_FACING_BACK;<br>
+Â Â Â Â Â Â Â Â break;<br>
+Â Â Â Â case CAMERA_FACING_EXTERNAL:<br>
+Â Â Â Â Â Â Â Â lensFacing = ANDROID_LENS_FACING_EXTERNAL;<br>
+Â Â Â Â Â Â Â Â break;<br>
+Â Â Â Â }<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_LENS_FACING, lensFacing);<br>
+<br>
+Â Â Â Â std::vector<float> lensFocalLengths = {<br>
+Â Â Â Â Â Â Â Â 1,<br>
+Â Â Â Â };<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â lensFocalLengths);<br>
+<br>
+Â Â Â Â std::vector<uint8_t> opticalStabilizations = {<br>
+Â Â Â Â Â Â Â Â ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF,<br>
+Â Â Â Â };<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â opticalStabilizations);<br>
+<br>
+Â Â Â Â float hypeFocalDistance = 0;<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â hypeFocalDistance);<br>
+<br>
+Â Â Â Â float minFocusDistance = 0;<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â minFocusDistance);<br>
+<br>
+Â Â Â Â /* Noise reduction modes. */<br>
+Â Â Â Â {<br>
+Â Â Â Â Â Â Â Â std::vector<uint8_t> data;<br>
+Â Â Â Â Â Â Â Â data.reserve(5);<br>
+Â Â Â Â Â Â Â Â const auto &infoMap = controlsInfo.find(&controls::draft::NoiseReductionMode);<br>
+Â Â Â Â Â Â Â Â if (infoMap != controlsInfo.end()) {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â for (const auto &value : infoMap->second.values())<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â data.push_back(value.get<int32_t>());<br>
+Â Â Â Â Â Â Â Â } else {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â data.push_back(ANDROID_NOISE_REDUCTION_MODE_OFF);<br>
+Â Â Â Â Â Â Â Â }<br>
+Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â data);<br>
+Â Â Â Â }<br>
+<br>
+Â Â Â Â /* Scaler static metadata. */<br>
+<br>
+Â Â Â Â /*<br>
+Â Â Â Â * \todo The digital zoom factor is a property that depends on the<br>
+Â Â Â Â * desired output configuration and the sensor frame size input to the<br>
+Â Â Â Â * ISP. This information is not available to the Android HAL, not at<br>
+Â Â Â Â * initialization time at least.<br>
+Â Â Â Â *<br>
+Â Â Â Â * As a workaround rely on pipeline handlers initializing the<br>
+Â Â Â Â * ScalerCrop control with the camera default configuration and use the<br>
+Â Â Â Â * maximum and minimum crop rectangles to calculate the digital zoom<br>
+Â Â Â Â * factor.<br>
+Â Â Â Â */<br>
+Â Â Â Â float maxZoom = 1.0f;<br>
+Â Â Â Â const auto scalerCrop = controlsInfo.find(&controls::ScalerCrop);<br>
+Â Â Â Â if (scalerCrop != controlsInfo.end()) {<br>
+Â Â Â Â Â Â Â Â Rectangle min = scalerCrop->second.min().get<Rectangle>();<br>
+Â Â Â Â Â Â Â Â Rectangle max = scalerCrop->second.max().get<Rectangle>();<br>
+Â Â Â Â Â Â Â Â maxZoom = std::min(1.0f * max.width / min.width,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â 1.0f * max.height / min.height);<br>
+Â Â Â Â }<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â maxZoom);<br>
+<br>
+Â Â Â Â std::vector<uint32_t> availableStreamConfigurations;<br>
+Â Â Â Â availableStreamConfigurations.reserve(streamConfigurations_.size() * 4);<br>
+Â Â Â Â for (const auto &entry : streamConfigurations_) {<br>
+Â Â Â Â Â Â Â Â availableStreamConfigurations.push_back(entry.androidFormat);<br>
+Â Â Â Â Â Â Â Â availableStreamConfigurations.push_back(entry.resolution.width);<br>
+Â Â Â Â Â Â Â Â availableStreamConfigurations.push_back(entry.resolution.height);<br>
+Â Â Â Â Â Â Â Â availableStreamConfigurations.push_back(<br>
+Â Â Â Â Â Â Â Â Â Â Â Â ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);<br>
+Â Â Â Â }<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableStreamConfigurations);<br>
+<br>
+Â Â Â Â std::vector<int64_t> availableStallDurations = {<br>
+Â Â Â Â Â Â Â Â ANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920, 33333333,<br>
+Â Â Â Â };<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableStallDurations);<br>
+<br>
+Â Â Â Â /* Use the minimum frame duration for all the YUV/RGB formats. */<br>
+Â Â Â Â if (minFrameDurationNsec > 0) {<br>
+Â Â Â Â Â Â Â Â std::vector<int64_t> minFrameDurations;<br>
+Â Â Â Â Â Â Â Â minFrameDurations.reserve(streamConfigurations_.size() * 4);<br>
+Â Â Â Â Â Â Â Â for (const auto &entry : streamConfigurations_) {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â minFrameDurations.push_back(entry.androidFormat);<br>
+Â Â Â Â Â Â Â Â Â Â Â Â minFrameDurations.push_back(entry.resolution.width);<br>
+Â Â Â Â Â Â Â Â Â Â Â Â minFrameDurations.push_back(entry.resolution.height);<br>
+Â Â Â Â Â Â Â Â Â Â Â Â minFrameDurations.push_back(minFrameDurationNsec);<br>
+Â Â Â Â Â Â Â Â }<br>
+Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â minFrameDurations);<br>
+Â Â Â Â }<br>
+<br>
+Â Â Â Â uint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY;<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_SCALER_CROPPING_TYPE, croppingType);<br>
+<br>
+Â Â Â Â /* Info static metadata. */<br>
+Â Â Â Â uint8_t supportedHWLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â supportedHWLevel);<br>
+<br>
+Â Â Â Â /* Request static metadata. */<br>
+Â Â Â Â int32_t partialResultCount = 1;<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_REQUEST_PARTIAL_RESULT_COUNT,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â partialResultCount);<br>
+<br>
+Â Â Â Â {<br>
+Â Â Â Â Â Â Â Â /* Default the value to 2 if not reported by the camera. */<br>
+Â Â Â Â Â Â Â Â uint8_t maxPipelineDepth = 2;<br>
+Â Â Â Â Â Â Â Â const auto &infoMap = controlsInfo.find(&controls::draft::PipelineDepth);<br>
+Â Â Â Â Â Â Â Â if (infoMap != controlsInfo.end())<br>
+Â Â Â Â Â Â Â Â Â Â Â Â maxPipelineDepth = infoMap->second.max().get<int32_t>();<br>
+Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_REQUEST_PIPELINE_MAX_DEPTH,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â maxPipelineDepth);<br>
+Â Â Â Â }<br>
+<br>
+Â Â Â Â /* LIMITED does not support reprocessing. */<br>
+Â Â Â Â uint32_t maxNumInputStreams = 0;<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â maxNumInputStreams);<br>
+<br>
+Â Â Â Â std::vector<uint8_t> availableCapabilities = {<br>
+Â Â Â Â Â Â Â Â ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,<br>
+Â Â Â Â };<br>
+<br>
+Â Â Â Â /* Report if camera supports RAW. */<br>
+Â Â Â Â bool rawStreamAvailable = false;<br>
+Â Â Â Â std::unique_ptr<CameraConfiguration> cameraConfig =<br>
+Â Â Â Â Â Â Â Â camera_->generateConfiguration({ StreamRole::Raw });<br>
+Â Â Â Â if (cameraConfig && !cameraConfig->empty()) {<br>
+Â Â Â Â Â Â Â Â const PixelFormatInfo &info =<br>
+Â Â Â Â Â Â Â Â Â Â Â Â PixelFormatInfo::info(cameraConfig->at(0).pixelFormat);<br>
+Â Â Â Â Â Â Â Â /* Only advertise RAW support if RAW16 is possible. */<br>
+Â Â Â Â Â Â Â Â if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW &&<br>
+Â Â Â Â Â Â Â Â Â Â info.bitsPerPixel == 16) {<br>
+Â Â Â Â Â Â Â Â Â Â Â Â rawStreamAvailable = true;<br>
+Â Â Â Â Â Â Â Â Â Â Â Â availableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);<br>
+Â Â Â Â Â Â Â Â }<br>
+Â Â Â Â }<br>
+<br>
+Â Â Â Â /* Number of { RAW, YUV, JPEG } supported output streams */<br>
+Â Â Â Â int32_t numOutStreams[] = { rawStreamAvailable, 2, 1 };<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â numOutStreams);<br>
+<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CAPABILITIES,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableCapabilities);<br>
+<br>
+Â Â Â Â std::vector<int32_t> availableCharacteristicsKeys = {<br>
+Â Â Â Â Â Â Â Â ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_AVAILABLE_MODES,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_COMPENSATION_RANGE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_COMPENSATION_STEP,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_LOCK_AVAILABLE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AF_AVAILABLE_MODES,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AVAILABLE_EFFECTS,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AVAILABLE_MODES,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AVAILABLE_SCENE_MODES,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AWB_AVAILABLE_MODES,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AWB_LOCK_AVAILABLE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_MAX_REGIONS,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_SCENE_MODE_OVERRIDES,<br>
+Â Â Â Â Â Â Â Â ANDROID_FLASH_INFO_AVAILABLE,<br>
+Â Â Â Â Â Â Â Â ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,<br>
+Â Â Â Â Â Â Â Â ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,<br>
+Â Â Â Â Â Â Â Â ANDROID_JPEG_MAX_SIZE,<br>
+Â Â Â Â Â Â Â Â ANDROID_LENS_FACING,<br>
+Â Â Â Â Â Â Â Â ANDROID_LENS_INFO_AVAILABLE_APERTURES,<br>
+Â Â Â Â Â Â Â Â ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,<br>
+Â Â Â Â Â Â Â Â ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,<br>
+Â Â Â Â Â Â Â Â ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,<br>
+Â Â Â Â Â Â Â Â ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,<br>
+Â Â Â Â Â Â Â Â ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,<br>
+Â Â Â Â Â Â Â Â ANDROID_REQUEST_AVAILABLE_CAPABILITIES,<br>
+Â Â Â Â Â Â Â Â ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,<br>
+Â Â Â Â Â Â Â Â ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,<br>
+Â Â Â Â Â Â Â Â ANDROID_REQUEST_PARTIAL_RESULT_COUNT,<br>
+Â Â Â Â Â Â Â Â ANDROID_REQUEST_PIPELINE_MAX_DEPTH,<br>
+Â Â Â Â Â Â Â Â ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,<br>
+Â Â Â Â Â Â Â Â ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,<br>
+Â Â Â Â Â Â Â Â ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,<br>
+Â Â Â Â Â Â Â Â ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,<br>
+Â Â Â Â Â Â Â Â ANDROID_SCALER_CROPPING_TYPE,<br>
+Â Â Â Â Â Â Â Â ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,<br>
+Â Â Â Â Â Â Â Â ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,<br>
+Â Â Â Â Â Â Â Â ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,<br>
+Â Â Â Â Â Â Â Â ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,<br>
+Â Â Â Â Â Â Â Â ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,<br>
+Â Â Â Â Â Â Â Â ANDROID_SENSOR_INFO_PHYSICAL_SIZE,<br>
+Â Â Â Â Â Â Â Â ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,<br>
+Â Â Â Â Â Â Â Â ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,<br>
+Â Â Â Â Â Â Â Â ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,<br>
+Â Â Â Â Â Â Â Â ANDROID_SENSOR_ORIENTATION,<br>
+Â Â Â Â Â Â Â Â ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,<br>
+Â Â Â Â Â Â Â Â ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,<br>
+Â Â Â Â Â Â Â Â ANDROID_SYNC_MAX_LATENCY,<br>
+Â Â Â Â };<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableCharacteristicsKeys);<br>
+<br>
+Â Â Â Â std::vector<int32_t> availableRequestKeys = {<br>
+Â Â Â Â Â Â Â Â ANDROID_COLOR_CORRECTION_ABERRATION_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_ANTIBANDING_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_LOCK,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_TARGET_FPS_RANGE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AF_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AF_TRIGGER,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AWB_LOCK,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AWB_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_CAPTURE_INTENT,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_EFFECT_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_SCENE_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_FLASH_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_JPEG_ORIENTATION,<br>
+Â Â Â Â Â Â Â Â ANDROID_JPEG_QUALITY,<br>
+Â Â Â Â Â Â Â Â ANDROID_JPEG_THUMBNAIL_QUALITY,<br>
+Â Â Â Â Â Â Â Â ANDROID_JPEG_THUMBNAIL_SIZE,<br>
+Â Â Â Â Â Â Â Â ANDROID_LENS_APERTURE,<br>
+Â Â Â Â Â Â Â Â ANDROID_LENS_OPTICAL_STABILIZATION_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_NOISE_REDUCTION_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_SCALER_CROP_REGION,<br>
+Â Â Â Â Â Â Â Â ANDROID_STATISTICS_FACE_DETECT_MODE<br>
+Â Â Â Â };<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableRequestKeys);<br>
+<br>
+Â Â Â Â std::vector<int32_t> availableResultKeys = {<br>
+Â Â Â Â Â Â Â Â ANDROID_COLOR_CORRECTION_ABERRATION_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_ANTIBANDING_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_LOCK,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_STATE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_TARGET_FPS_RANGE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AF_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AF_STATE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AF_TRIGGER,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AWB_LOCK,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AWB_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_AWB_STATE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_CAPTURE_INTENT,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_EFFECT_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_SCENE_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_FLASH_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_FLASH_STATE,<br>
+Â Â Â Â Â Â Â Â ANDROID_JPEG_GPS_COORDINATES,<br>
+Â Â Â Â Â Â Â Â ANDROID_JPEG_GPS_PROCESSING_METHOD,<br>
+Â Â Â Â Â Â Â Â ANDROID_JPEG_GPS_TIMESTAMP,<br>
+Â Â Â Â Â Â Â Â ANDROID_JPEG_ORIENTATION,<br>
+Â Â Â Â Â Â Â Â ANDROID_JPEG_QUALITY,<br>
+Â Â Â Â Â Â Â Â ANDROID_JPEG_SIZE,<br>
+Â Â Â Â Â Â Â Â ANDROID_JPEG_THUMBNAIL_QUALITY,<br>
+Â Â Â Â Â Â Â Â ANDROID_JPEG_THUMBNAIL_SIZE,<br>
+Â Â Â Â Â Â Â Â ANDROID_LENS_APERTURE,<br>
+Â Â Â Â Â Â Â Â ANDROID_LENS_FOCAL_LENGTH,<br>
+Â Â Â Â Â Â Â Â ANDROID_LENS_OPTICAL_STABILIZATION_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_LENS_STATE,<br>
+Â Â Â Â Â Â Â Â ANDROID_NOISE_REDUCTION_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_REQUEST_PIPELINE_DEPTH,<br>
+Â Â Â Â Â Â Â Â ANDROID_SCALER_CROP_REGION,<br>
+Â Â Â Â Â Â Â Â ANDROID_SENSOR_EXPOSURE_TIME,<br>
+Â Â Â Â Â Â Â Â ANDROID_SENSOR_FRAME_DURATION,<br>
+Â Â Â Â Â Â Â Â ANDROID_SENSOR_ROLLING_SHUTTER_SKEW,<br>
+Â Â Â Â Â Â Â Â ANDROID_SENSOR_TEST_PATTERN_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_SENSOR_TIMESTAMP,<br>
+Â Â Â Â Â Â Â Â ANDROID_STATISTICS_FACE_DETECT_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,<br>
+Â Â Â Â Â Â Â Â ANDROID_STATISTICS_SCENE_FLICKER,<br>
+Â Â Â Â };<br>
+Â Â Â Â staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableResultKeys);<br>
+<br>
+Â Â Â Â if (!staticMetadata_->isValid()) {<br>
+Â Â Â Â Â Â Â Â LOG(HAL, Error) << "Failed to construct static metadata";<br>
+Â Â Â Â Â Â Â Â staticMetadata_.reset();<br>
+Â Â Â Â Â Â Â Â return -EINVAL;<br>
+Â Â Â Â }<br>
+<br>
+Â Â Â Â if (staticMetadata_->resized()) {<br>
+Â Â Â Â Â Â Â Â auto [entryCount, dataCount] = staticMetadata_->usage();<br>
+Â Â Â Â Â Â Â Â LOG(HAL, Info)<br>
+Â Â Â Â Â Â Â Â Â Â Â Â << "Static metadata resized: " << entryCount<br>
+Â Â Â Â Â Â Â Â Â Â Â Â << " entries and " << dataCount << " bytes used";<br>
+Â Â Â Â }<br>
+<br>
+Â Â Â Â return 0;<br>
+}<br>
+<br>
+/* Translate Android format code to libcamera pixel format. */<br>
+PixelFormat CameraCapabilities::toPixelFormat(int format) const<br>
+{<br>
+Â Â Â Â auto it = formatsMap_.find(format);<br>
+Â Â Â Â if (it == formatsMap_.end()) {<br>
+Â Â Â Â Â Â Â Â LOG(HAL, Error) << "Requested format " << utils::hex(format)<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << " not supported";<br>
+Â Â Â Â Â Â Â Â return PixelFormat();<br>
+Â Â Â Â }<br>
+<br>
+Â Â Â Â return it->second;<br>
+}<br>
+<br>
+std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplatePreview() const<br>
+{<br>
+Â Â Â Â /*<br>
+Â Â Â Â * \todo Keep this in sync with the actual number of entries.<br>
+Â Â Â Â * Currently: 20 entries, 35 bytes<br>
+Â Â Â Â */<br>
+Â Â Â Â auto requestTemplate = std::make_unique<CameraMetadata>(21, 36);<br>
+Â Â Â Â if (!requestTemplate->isValid()) {<br>
+Â Â Â Â Â Â Â Â return nullptr;<br>
+Â Â Â Â }<br>
+<br>
+Â Â Â Â /* Get the FPS range registered in the static metadata. */<br>
+Â Â Â Â camera_metadata_ro_entry_t entry;<br>
+Â Â Â Â bool found = staticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â &entry);<br>
+Â Â Â Â if (!found) {<br>
+Â Â Â Â Â Â Â Â LOG(HAL, Error) << "Cannot create capture template without FPS range";<br>
+Â Â Â Â Â Â Â Â return nullptr;<br>
+Â Â Â Â }<br>
+<br>
+Â Â Â Â /*<br>
+Â Â Â Â * Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata<br>
+Â Â Â Â * has been assembled as {{min, max} {max, max}}.<br>
+Â Â Â Â */<br>
+Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â entry.data.i32, 2);<br>
+<br>
+Â Â Â Â uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;<br>
+Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_AE_MODE, aeMode);<br>
+<br>
+Â Â Â Â int32_t aeExposureCompensation = 0;<br>
+Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â aeExposureCompensation);<br>
+<br>
+Â Â Â Â uint8_t aePrecaptureTrigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;<br>
+Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â aePrecaptureTrigger);<br>
+<br>
+Â Â Â Â uint8_t aeLock = ANDROID_CONTROL_AE_LOCK_OFF;<br>
+Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_AE_LOCK, aeLock);<br>
+<br>
+Â Â Â Â uint8_t aeAntibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;<br>
+Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_AE_ANTIBANDING_MODE,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â aeAntibandingMode);<br>
+<br>
+Â Â Â Â uint8_t afMode = ANDROID_CONTROL_AF_MODE_OFF;<br>
+Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_AF_MODE, afMode);<br>
+<br>
+Â Â Â Â uint8_t afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;<br>
+Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_AF_TRIGGER, afTrigger);<br>
+<br>
+Â Â Â Â uint8_t awbMode = ANDROID_CONTROL_AWB_MODE_AUTO;<br>
+Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_AWB_MODE, awbMode);<br>
+<br>
+Â Â Â Â uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;<br>
+Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_AWB_LOCK, awbLock);<br>
+<br>
+Â Â Â Â uint8_t flashMode = ANDROID_FLASH_MODE_OFF;<br>
+Â Â Â Â requestTemplate->addEntry(ANDROID_FLASH_MODE, flashMode);<br>
+<br>
+Â Â Â Â uint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;<br>
+Â Â Â Â requestTemplate->addEntry(ANDROID_STATISTICS_FACE_DETECT_MODE,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â faceDetectMode);<br>
+<br>
+Â Â Â Â uint8_t noiseReduction = ANDROID_NOISE_REDUCTION_MODE_OFF;<br>
+Â Â Â Â requestTemplate->addEntry(ANDROID_NOISE_REDUCTION_MODE,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â noiseReduction);<br>
+<br>
+Â Â Â Â uint8_t aberrationMode = ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF;<br>
+Â Â Â Â requestTemplate->addEntry(ANDROID_COLOR_CORRECTION_ABERRATION_MODE,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â aberrationMode);<br>
+<br>
+Â Â Â Â uint8_t controlMode = ANDROID_CONTROL_MODE_AUTO;<br>
+Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_MODE, controlMode);<br>
+<br>
+Â Â Â Â float lensAperture = 2.53 / 100;<br>
+Â Â Â Â requestTemplate->addEntry(ANDROID_LENS_APERTURE, lensAperture);<br>
+<br>
+Â Â Â Â uint8_t opticalStabilization = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;<br>
+Â Â Â Â requestTemplate->addEntry(ANDROID_LENS_OPTICAL_STABILIZATION_MODE,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â opticalStabilization);<br>
+<br>
+Â Â Â Â uint8_t captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;<br>
+Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_CAPTURE_INTENT,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â captureIntent);<br>
+<br>
+Â Â Â Â return requestTemplate;<br>
+}<br>
+<br>
+std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplateVideo() const<br>
+{<br>
+Â Â Â Â std::unique_ptr<CameraMetadata> previewTemplate = requestTemplatePreview();<br>
+Â Â Â Â if (!previewTemplate)<br>
+Â Â Â Â Â Â Â Â return nullptr;<br>
+<br>
+Â Â Â Â /*<br>
+Â Â Â Â * The video template requires a fixed FPS range. Everything else<br>
+Â Â Â Â * stays the same as the preview template.<br>
+Â Â Â Â */<br>
+Â Â Â Â camera_metadata_ro_entry_t entry;<br>
+Â Â Â Â staticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â &entry);<br>
+<br>
+Â Â Â Â /*<br>
+Â Â Â Â * Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata<br>
+Â Â Â Â * has been assembled as {{min, max} {max, max}}.<br>
+Â Â Â Â */<br>
+Â Â Â Â previewTemplate->updateEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â entry.data.i32 + 2, 2);<br>
+<br>
+Â Â Â Â return previewTemplate;<br>
+}<br>
diff --git a/src/android/camera_capabilities.h b/src/android/camera_capabilities.h<br>
new file mode 100644<br>
index 000000000000..f511607bbd90<br>
--- /dev/null<br>
+++ b/src/android/camera_capabilities.h<br>
@@ -0,0 +1,65 @@<br>
+/* SPDX-License-Identifier: LGPL-2.1-or-later */<br>
+/*<br>
+ * Copyright (C) 2021, Google Inc.<br>
+ *<br>
+ * camera_capabilities.h - Camera static properties manager<br>
+ */<br>
+#ifndef __ANDROID_CAMERA_CAPABILITIES_H__<br>
+#define __ANDROID_CAMERA_CAPABILITIES_H__<br>
+<br>
+#include <map><br>
+#include <memory><br>
+#include <vector><br>
+<br>
+#include <libcamera/camera.h><br>
+#include <libcamera/class.h><br>
+#include <libcamera/formats.h><br>
+#include <libcamera/geometry.h><br>
+<br>
+#include "camera_metadata.h"<br>
+<br>
+class CameraCapabilities<br>
+{<br>
+public:<br>
+Â Â Â Â CameraCapabilities() = default;<br>
+<br>
+Â Â Â Â int initialize(std::shared_ptr<libcamera::Camera> camera,<br>
+Â Â Â Â Â Â Â Â Â Â Â int orientation, int facing);<br>
+<br>
+Â Â Â Â CameraMetadata *staticMetadata() const { return staticMetadata_.get(); }<br>
+Â Â Â Â libcamera::PixelFormat toPixelFormat(int format) const;<br>
+Â Â Â Â unsigned int maxJpegBufferSize() const { return maxJpegBufferSize_; }<br>
+<br>
+Â Â Â Â std::unique_ptr<CameraMetadata> requestTemplatePreview() const;<br>
+Â Â Â Â std::unique_ptr<CameraMetadata> requestTemplateVideo() const;<br>
+<br>
+private:<br>
+Â Â Â Â LIBCAMERA_DISABLE_COPY_AND_MOVE(CameraCapabilities)<br>
+<br>
+Â Â Â Â struct Camera3StreamConfiguration {<br>
+Â Â Â Â Â Â Â Â libcamera::Size resolution;<br>
+Â Â Â Â Â Â Â Â int androidFormat;<br>
+Â Â Â Â };<br>
+<br>
+Â Â Â Â std::vector<libcamera::Size><br>
+Â Â Â Â getYUVResolutions(libcamera::CameraConfiguration *cameraConfig,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â const libcamera::PixelFormat &pixelFormat,<br>
+Â Â Â Â Â Â Â Â Â Â Â Â Â const std::vector<libcamera::Size> &resolutions);<br>
+Â Â Â Â std::vector<libcamera::Size><br>
+Â Â Â Â getRawResolutions(const libcamera::PixelFormat &pixelFormat);<br>
+Â Â Â Â int initializeStreamConfigurations();<br>
+<br>
+Â Â Â Â int initializeStaticMetadata();<br>
+<br>
+Â Â Â Â std::shared_ptr<libcamera::Camera> camera_;<br>
+<br>
+Â Â Â Â int facing_;<br>
+Â Â Â Â int orientation_;<br>
+<br>
+Â Â Â Â std::vector<Camera3StreamConfiguration> streamConfigurations_;<br>
+Â Â Â Â std::map<int, libcamera::PixelFormat> formatsMap_;<br>
+Â Â Â Â std::unique_ptr<CameraMetadata> staticMetadata_;<br>
+Â Â Â Â unsigned int maxJpegBufferSize_;<br>
+};<br>
+<br>
+#endif /* __ANDROID_CAMERA_CAPABILITIES_H__ */<br>
diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp<br>
index 8c71fd0675d3..4bd125d7020a 100644<br>
--- a/src/android/camera_device.cpp<br>
+++ b/src/android/camera_device.cpp<br>
@@ -10,11 +10,8 @@<br>
 #include "camera_ops.h"<br>
 #include "post_processor.h"<br>
<br>
-#include <array><br>
-#include <cmath><br>
 #include <fstream><br>
 #include <sys/mman.h><br>
-#include <tuple><br>
 #include <unistd.h><br>
 #include <vector><br>
<br>
@@ -23,7 +20,6 @@<br>
 #include <libcamera/formats.h><br>
 #include <libcamera/property_ids.h><br>
<br>
-#include "libcamera/internal/formats.h"<br>
 #include "libcamera/internal/log.h"<br>
 #include "libcamera/internal/thread.h"<br>
 #include "libcamera/internal/utils.h"<br>
@@ -36,94 +32,6 @@ LOG_DECLARE_CATEGORY(HAL)<br>
<br>
 namespace {<br>
<br>
-/*<br>
- * \var camera3Resolutions<br>
- * \brief The list of image resolutions defined as mandatory to be supported by<br>
- * the Android Camera3 specification<br>
- */<br>
-const std::vector<Size> camera3Resolutions = {<br>
-Â Â Â Â { 320, 240 },<br>
-Â Â Â Â { 640, 480 },<br>
-Â Â Â Â { 1280, 720 },<br>
-Â Â Â Â { 1920, 1080 }<br>
-};<br>
-<br>
-/*<br>
- * \struct Camera3Format<br>
- * \brief Data associated with an Android format identifier<br>
- * \var libcameraFormats List of libcamera pixel formats compatible with the<br>
- * Android format<br>
- * \var name The human-readable representation of the Android format code<br>
- */<br>
-struct Camera3Format {<br>
-Â Â Â Â std::vector<PixelFormat> libcameraFormats;<br>
-Â Â Â Â bool mandatory;<br>
-Â Â Â Â const char *name;<br>
-};<br>
-<br>
-/*<br>
- * \var camera3FormatsMap<br>
- * \brief Associate Android format code with ancillary data<br>
- */<br>
-const std::map<int, const Camera3Format> camera3FormatsMap = {<br>
-Â Â Â Â {<br>
-Â Â Â Â Â Â Â Â HAL_PIXEL_FORMAT_BLOB, {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â { formats::MJPEG },<br>
-Â Â Â Â Â Â Â Â Â Â Â Â true,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â "BLOB"<br>
-Â Â Â Â Â Â Â Â }<br>
-Â Â Â Â }, {<br>
-Â Â Â Â Â Â Â Â HAL_PIXEL_FORMAT_YCbCr_420_888, {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â { formats::NV12, formats::NV21 },<br>
-Â Â Â Â Â Â Â Â Â Â Â Â true,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â "YCbCr_420_888"<br>
-Â Â Â Â Â Â Â Â }<br>
-Â Â Â Â }, {<br>
-Â Â Â Â Â Â Â Â /*<br>
-Â Â Â Â Â Â Â Â * \todo Translate IMPLEMENTATION_DEFINED inspecting the gralloc<br>
-Â Â Â Â Â Â Â Â * usage flag. For now, copy the YCbCr_420 configuration.<br>
-Â Â Â Â Â Â Â Â */<br>
-Â Â Â Â Â Â Â Â HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â { formats::NV12, formats::NV21 },<br>
-Â Â Â Â Â Â Â Â Â Â Â Â true,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â "IMPLEMENTATION_DEFINED"<br>
-Â Â Â Â Â Â Â Â }<br>
-Â Â Â Â }, {<br>
-Â Â Â Â Â Â Â Â HAL_PIXEL_FORMAT_RAW10, {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SBGGR10_CSI2P,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SGBRG10_CSI2P,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SGRBG10_CSI2P,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SRGGB10_CSI2P<br>
-Â Â Â Â Â Â Â Â Â Â Â Â },<br>
-Â Â Â Â Â Â Â Â Â Â Â Â false,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â "RAW10"<br>
-Â Â Â Â Â Â Â Â }<br>
-Â Â Â Â }, {<br>
-Â Â Â Â Â Â Â Â HAL_PIXEL_FORMAT_RAW12, {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SBGGR12_CSI2P,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SGBRG12_CSI2P,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SGRBG12_CSI2P,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SRGGB12_CSI2P<br>
-Â Â Â Â Â Â Â Â Â Â Â Â },<br>
-Â Â Â Â Â Â Â Â Â Â Â Â false,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â "RAW12"<br>
-Â Â Â Â Â Â Â Â }<br>
-Â Â Â Â }, {<br>
-Â Â Â Â Â Â Â Â HAL_PIXEL_FORMAT_RAW16, {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SBGGR16,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SGBRG16,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SGRBG16,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â formats::SRGGB16<br>
-Â Â Â Â Â Â Â Â Â Â Â Â },<br>
-Â Â Â Â Â Â Â Â Â Â Â Â false,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â "RAW16"<br>
-Â Â Â Â Â Â Â Â }<br>
-Â Â Â Â },<br>
-};<br>
-<br>
 /*<br>
 * \struct Camera3StreamConfig<br>
 * \brief Data to store StreamConfiguration associated with camera3_stream(s)<br>
@@ -512,242 +420,7 @@ int CameraDevice::initialize(const CameraConfigData *cameraConfigData)<br>
        orientation_ = 0;<br>
    }<br>
<br>
-Â Â Â Â /* Acquire the camera and initialize available stream configurations. */<br>
-Â Â Â Â int ret = camera_->acquire();<br>
-Â Â Â Â if (ret) {<br>
-Â Â Â Â Â Â Â Â LOG(HAL, Error) << "Failed to temporarily acquire the camera";<br>
-Â Â Â Â Â Â Â Â return ret;<br>
-Â Â Â Â }<br>
-<br>
-Â Â Â Â ret = initializeStreamConfigurations();<br>
-Â Â Â Â camera_->release();<br>
-Â Â Â Â return ret;<br>
-}<br>
-<br>
-std::vector<Size> CameraDevice::getYUVResolutions(CameraConfiguration *cameraConfig,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â const PixelFormat &pixelFormat,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â const std::vector<Size> &resolutions)<br>
-{<br>
-Â Â Â Â std::vector<Size> supportedResolutions;<br>
-<br>
-Â Â Â Â StreamConfiguration &cfg = cameraConfig->at(0);<br>
-Â Â Â Â for (const Size &res : resolutions) {<br>
-Â Â Â Â Â Â Â Â cfg.pixelFormat = pixelFormat;<br>
-Â Â Â Â Â Â Â Â cfg.size = res;<br>
-<br>
-Â Â Â Â Â Â Â Â CameraConfiguration::Status status = cameraConfig->validate();<br>
-Â Â Â Â Â Â Â Â if (status != CameraConfiguration::Valid) {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â LOG(HAL, Debug) << cfg.toString() << " not supported";<br>
-Â Â Â Â Â Â Â Â Â Â Â Â continue;<br>
-Â Â Â Â Â Â Â Â }<br>
-<br>
-Â Â Â Â Â Â Â Â LOG(HAL, Debug) << cfg.toString() << " supported";<br>
-<br>
-Â Â Â Â Â Â Â Â supportedResolutions.push_back(res);<br>
-Â Â Â Â }<br>
-<br>
-Â Â Â Â return supportedResolutions;<br>
-}<br>
-<br>
-std::vector<Size> CameraDevice::getRawResolutions(const libcamera::PixelFormat &pixelFormat)<br>
-{<br>
-Â Â Â Â std::unique_ptr<CameraConfiguration> cameraConfig =<br>
-Â Â Â Â Â Â Â Â camera_->generateConfiguration({ StreamRole::Raw });<br>
-Â Â Â Â StreamConfiguration &cfg = cameraConfig->at(0);<br>
-Â Â Â Â const StreamFormats &formats = cfg.formats();<br>
-Â Â Â Â std::vector<Size> supportedResolutions = formats.sizes(pixelFormat);<br>
-<br>
-Â Â Â Â return supportedResolutions;<br>
-}<br>
-<br>
-/*<br>
- * Initialize the format conversion map to translate from Android format<br>
- * identifier to libcamera pixel formats and fill in the list of supported<br>
- * stream configurations to be reported to the Android camera framework through<br>
- * the static stream configuration metadata.<br>
- */<br>
-int CameraDevice::initializeStreamConfigurations()<br>
-{<br>
-Â Â Â Â /*<br>
-Â Â Â Â * Get the maximum output resolutions<br>
-Â Â Â Â * \todo Get this from the camera properties once defined<br>
-Â Â Â Â */<br>
-Â Â Â Â std::unique_ptr<CameraConfiguration> cameraConfig =<br>
-Â Â Â Â Â Â Â Â camera_->generateConfiguration({ StillCapture });<br>
-Â Â Â Â if (!cameraConfig) {<br>
-Â Â Â Â Â Â Â Â LOG(HAL, Error) << "Failed to get maximum resolution";<br>
-Â Â Â Â Â Â Â Â return -EINVAL;<br>
-Â Â Â Â }<br>
-Â Â Â Â StreamConfiguration &cfg = cameraConfig->at(0);<br>
-<br>
-Â Â Â Â /*<br>
-Â Â Â Â * \todo JPEG - Adjust the maximum available resolution by taking the<br>
-Â Â Â Â * JPEG encoder requirements into account (alignment and aspect ratio).<br>
-Â Â Â Â */<br>
-Â Â Â Â const Size maxRes = cfg.size;<br>
-Â Â Â Â LOG(HAL, Debug) << "Maximum supported resolution: " << maxRes.toString();<br>
-<br>
-Â Â Â Â /*<br>
-Â Â Â Â * Build the list of supported image resolutions.<br>
-Â Â Â Â *<br>
-Â Â Â Â * The resolutions listed in camera3Resolution are mandatory to be<br>
-Â Â Â Â * supported, up to the camera maximum resolution.<br>
-Â Â Â Â *<br>
-Â Â Â Â * Augment the list by adding resolutions calculated from the camera<br>
-Â Â Â Â * maximum one.<br>
-Â Â Â Â */<br>
-Â Â Â Â std::vector<Size> cameraResolutions;<br>
-Â Â Â Â std::copy_if(camera3Resolutions.begin(), camera3Resolutions.end(),<br>
-Â Â Â Â Â Â Â Â Â Â std::back_inserter(cameraResolutions),<br>
-Â Â Â Â Â Â Â Â Â Â [&](const Size &res) { return res < maxRes; });<br>
-<br>
-Â Â Â Â /*<br>
-Â Â Â Â * The Camera3 specification suggests adding 1/2 and 1/4 of the maximum<br>
-Â Â Â Â * resolution.<br>
-Â Â Â Â */<br>
-Â Â Â Â for (unsigned int divider = 2;; divider <<= 1) {<br>
-Â Â Â Â Â Â Â Â Size derivedSize{<br>
-Â Â Â Â Â Â Â Â Â Â Â Â maxRes.width / divider,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â maxRes.height / divider,<br>
-Â Â Â Â Â Â Â Â };<br>
-<br>
-Â Â Â Â Â Â Â Â if (derivedSize.width < 320 ||<br>
-Â Â Â Â Â Â Â Â Â Â derivedSize.height < 240)<br>
-Â Â Â Â Â Â Â Â Â Â Â Â break;<br>
-<br>
-Â Â Â Â Â Â Â Â cameraResolutions.push_back(derivedSize);<br>
-Â Â Â Â }<br>
-Â Â Â Â cameraResolutions.push_back(maxRes);<br>
-<br>
-Â Â Â Â /* Remove duplicated entries from the list of supported resolutions. */<br>
-Â Â Â Â std::sort(cameraResolutions.begin(), cameraResolutions.end());<br>
-Â Â Â Â auto last = std::unique(cameraResolutions.begin(), cameraResolutions.end());<br>
-Â Â Â Â cameraResolutions.erase(last, cameraResolutions.end());<br>
-<br>
-Â Â Â Â /*<br>
-Â Â Â Â * Build the list of supported camera formats.<br>
-Â Â Â Â *<br>
-Â Â Â Â * To each Android format a list of compatible libcamera formats is<br>
-Â Â Â Â * associated. The first libcamera format that tests successful is added<br>
-Â Â Â Â * to the format translation map used when configuring the streams.<br>
-Â Â Â Â * It is then tested against the list of supported camera resolutions to<br>
-Â Â Â Â * build the stream configuration map reported through the camera static<br>
-Â Â Â Â * metadata.<br>
-Â Â Â Â */<br>
-Â Â Â Â Size maxJpegSize;<br>
-Â Â Â Â for (const auto &format : camera3FormatsMap) {<br>
-Â Â Â Â Â Â Â Â int androidFormat = format.first;<br>
-Â Â Â Â Â Â Â Â const Camera3Format &camera3Format = format.second;<br>
-Â Â Â Â Â Â Â Â const std::vector<PixelFormat> &libcameraFormats =<br>
-Â Â Â Â Â Â Â Â Â Â Â Â camera3Format.libcameraFormats;<br>
-<br>
-Â Â Â Â Â Â Â Â LOG(HAL, Debug) << "Trying to map Android format "<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << camera3Format.name;<br>
-<br>
-Â Â Â Â Â Â Â Â /*<br>
-Â Â Â Â Â Â Â Â * JPEG is always supported, either produced directly by the<br>
-Â Â Â Â Â Â Â Â * camera, or encoded in the HAL.<br>
-Â Â Â Â Â Â Â Â */<br>
-Â Â Â Â Â Â Â Â if (androidFormat == HAL_PIXEL_FORMAT_BLOB) {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â formatsMap_[androidFormat] = formats::MJPEG;<br>
-Â Â Â Â Â Â Â Â Â Â Â Â LOG(HAL, Debug) << "Mapped Android format "<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << camera3Format.name << " to "<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << formats::MJPEG.toString()<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << " (fixed mapping)";<br>
-Â Â Â Â Â Â Â Â Â Â Â Â continue;<br>
-Â Â Â Â Â Â Â Â }<br>
-<br>
-Â Â Â Â Â Â Â Â /*<br>
-Â Â Â Â Â Â Â Â * Test the libcamera formats that can produce images<br>
-Â Â Â Â Â Â Â Â * compatible with the format defined by Android.<br>
-Â Â Â Â Â Â Â Â */<br>
-Â Â Â Â Â Â Â Â PixelFormat mappedFormat;<br>
-Â Â Â Â Â Â Â Â for (const PixelFormat &pixelFormat : libcameraFormats) {<br>
-<br>
-Â Â Â Â Â Â Â Â Â Â Â Â LOG(HAL, Debug) << "Testing " << pixelFormat.toString();<br>
-<br>
-Â Â Â Â Â Â Â Â Â Â Â Â /*<br>
-Â Â Â Â Â Â Â Â Â Â Â Â * The stream configuration size can be adjusted,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â * not the pixel format.<br>
-Â Â Â Â Â Â Â Â Â Â Â Â *<br>
-Â Â Â Â Â Â Â Â Â Â Â Â * \todo This could be simplified once all pipeline<br>
-Â Â Â Â Â Â Â Â Â Â Â Â * handlers will report the StreamFormats list of<br>
-Â Â Â Â Â Â Â Â Â Â Â Â * supported formats.<br>
-Â Â Â Â Â Â Â Â Â Â Â Â */<br>
-Â Â Â Â Â Â Â Â Â Â Â Â cfg.pixelFormat = pixelFormat;<br>
-<br>
-Â Â Â Â Â Â Â Â Â Â Â Â CameraConfiguration::Status status = cameraConfig->validate();<br>
-Â Â Â Â Â Â Â Â Â Â Â Â if (status != CameraConfiguration::Invalid &&<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â cfg.pixelFormat == pixelFormat) {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â mappedFormat = pixelFormat;<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;<br>
-Â Â Â Â Â Â Â Â Â Â Â Â }<br>
-Â Â Â Â Â Â Â Â }<br>
-<br>
-Â Â Â Â Â Â Â Â if (!mappedFormat.isValid()) {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â /* If the format is not mandatory, skip it. */<br>
-Â Â Â Â Â Â Â Â Â Â Â Â if (!camera3Format.mandatory)<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â continue;<br>
-<br>
-Â Â Â Â Â Â Â Â Â Â Â Â LOG(HAL, Error)<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << "Failed to map mandatory Android format "<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << camera3Format.name << " ("<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << utils::hex(androidFormat) << "): aborting";<br>
-Â Â Â Â Â Â Â Â Â Â Â Â return -EINVAL;<br>
-Â Â Â Â Â Â Â Â }<br>
-<br>
-Â Â Â Â Â Â Â Â /*<br>
-Â Â Â Â Â Â Â Â * Record the mapping and then proceed to generate the<br>
-Â Â Â Â Â Â Â Â * stream configurations map, by testing the image resolutions.<br>
-Â Â Â Â Â Â Â Â */<br>
-Â Â Â Â Â Â Â Â formatsMap_[androidFormat] = mappedFormat;<br>
-Â Â Â Â Â Â Â Â LOG(HAL, Debug) << "Mapped Android format "<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << camera3Format.name << " to "<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << mappedFormat.toString();<br>
-<br>
-Â Â Â Â Â Â Â Â std::vector<Size> resolutions;<br>
-Â Â Â Â Â Â Â Â const PixelFormatInfo &info = PixelFormatInfo::info(mappedFormat);<br>
-Â Â Â Â Â Â Â Â if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW)<br>
-Â Â Â Â Â Â Â Â Â Â Â Â resolutions = getRawResolutions(mappedFormat);<br>
-Â Â Â Â Â Â Â Â else<br>
-Â Â Â Â Â Â Â Â Â Â Â Â resolutions = getYUVResolutions(cameraConfig.get(),<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â mappedFormat,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â cameraResolutions);<br>
-<br>
-Â Â Â Â Â Â Â Â for (const Size &res : resolutions) {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â streamConfigurations_.push_back({ res, androidFormat });<br>
-<br>
-Â Â Â Â Â Â Â Â Â Â Â Â /*<br>
-Â Â Â Â Â Â Â Â Â Â Â Â * If the format is HAL_PIXEL_FORMAT_YCbCr_420_888<br>
-Â Â Â Â Â Â Â Â Â Â Â Â * from which JPEG is produced, add an entry for<br>
-Â Â Â Â Â Â Â Â Â Â Â Â * the JPEG stream.<br>
-Â Â Â Â Â Â Â Â Â Â Â Â *<br>
-Â Â Â Â Â Â Â Â Â Â Â Â * \todo Wire the JPEG encoder to query the supported<br>
-Â Â Â Â Â Â Â Â Â Â Â Â * sizes provided a list of formats it can encode.<br>
-Â Â Â Â Â Â Â Â Â Â Â Â *<br>
-Â Â Â Â Â Â Â Â Â Â Â Â * \todo Support JPEG streams produced by the Camera<br>
-Â Â Â Â Â Â Â Â Â Â Â Â * natively.<br>
-Â Â Â Â Â Â Â Â Â Â Â Â */<br>
-Â Â Â Â Â Â Â Â Â Â Â Â if (androidFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â streamConfigurations_.push_back(<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â { res, HAL_PIXEL_FORMAT_BLOB });<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â maxJpegSize = std::max(maxJpegSize, res);<br>
-Â Â Â Â Â Â Â Â Â Â Â Â }<br>
-Â Â Â Â Â Â Â Â }<br>
-<br>
-Â Â Â Â Â Â Â Â /*<br>
-Â Â Â Â Â Â Â Â * \todo Calculate the maximum JPEG buffer size by asking the<br>
-Â Â Â Â Â Â Â Â * encoder giving the maximum frame size required.<br>
-Â Â Â Â Â Â Â Â */<br>
-Â Â Â Â Â Â Â Â maxJpegBufferSize_ = maxJpegSize.width * maxJpegSize.height * 1.5;<br>
-Â Â Â Â }<br>
-<br>
-Â Â Â Â LOG(HAL, Debug) << "Collected stream configuration map: ";<br>
-Â Â Â Â for (const auto &entry : streamConfigurations_)<br>
-Â Â Â Â Â Â Â Â LOG(HAL, Debug) << "{ " << entry.resolution.toString() << " - "<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << utils::hex(entry.androidFormat) << " }";<br>
-<br>
-Â Â Â Â return 0;<br>
+Â Â Â Â return capabilities_.initialize(camera_, orientation_, facing_);<br>
 }<br>
<br>
 /*<br>
@@ -817,802 +490,19 @@ void CameraDevice::stop()<br>
    state_ = State::Stopped;<br>
 }<br>
<br>
-void CameraDevice::setCallbacks(const camera3_callback_ops_t *callbacks)<br>
+unsigned int CameraDevice::maxJpegBufferSize() const<br>
 {<br>
-Â Â Â Â callbacks_ = callbacks;<br>
+Â Â Â Â return capabilities_.maxJpegBufferSize();<br>
 }<br>
<br>
-/*<br>
- * Return static information for the camera.<br>
- */<br>
-const camera_metadata_t *CameraDevice::getStaticMetadata()<br>
-{<br>
-Â Â Â Â if (staticMetadata_)<br>
-Â Â Â Â Â Â Â Â return staticMetadata_->get();<br>
-<br>
-Â Â Â Â staticMetadata_ = std::make_unique<CameraMetadata>(64, 1024);<br>
-Â Â Â Â if (!staticMetadata_->isValid()) {<br>
-Â Â Â Â Â Â Â Â LOG(HAL, Error) << "Failed to allocate static metadata";<br>
-Â Â Â Â Â Â Â Â staticMetadata_.reset();<br>
-Â Â Â Â Â Â Â Â return nullptr;<br>
-Â Â Â Â }<br>
-<br>
-Â Â Â Â const ControlInfoMap &controlsInfo = camera_->controls();<br>
-Â Â Â Â const ControlList &properties = camera_->properties();<br>
-<br>
-Â Â Â Â /* Color correction static metadata. */<br>
-Â Â Â Â {<br>
-Â Â Â Â Â Â Â Â std::vector<uint8_t> data;<br>
-Â Â Â Â Â Â Â Â data.reserve(3);<br>
-Â Â Â Â Â Â Â Â const auto &infoMap = controlsInfo.find(&controls::draft::ColorCorrectionAberrationMode);<br>
-Â Â Â Â Â Â Â Â if (infoMap != controlsInfo.end()) {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â for (const auto &value : infoMap->second.values())<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â data.push_back(value.get<int32_t>());<br>
-Â Â Â Â Â Â Â Â } else {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â data.push_back(ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF);<br>
-Â Â Â Â Â Â Â Â }<br>
-Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â data);<br>
-Â Â Â Â }<br>
-<br>
-Â Â Â Â /* Control static metadata. */<br>
-Â Â Â Â std::vector<uint8_t> aeAvailableAntiBandingModes = {<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO,<br>
-Â Â Â Â };<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â aeAvailableAntiBandingModes);<br>
-<br>
-Â Â Â Â std::vector<uint8_t> aeAvailableModes = {<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_MODE_ON,<br>
-Â Â Â Â };<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_MODES,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â aeAvailableModes);<br>
-<br>
-Â Â Â Â int64_t minFrameDurationNsec = -1;<br>
-Â Â Â Â int64_t maxFrameDurationNsec = -1;<br>
-Â Â Â Â const auto frameDurationsInfo = controlsInfo.find(&controls::FrameDurationLimits);<br>
-Â Â Â Â if (frameDurationsInfo != controlsInfo.end()) {<br>
-Â Â Â Â Â Â Â Â minFrameDurationNsec = frameDurationsInfo->second.min().get<int64_t>() * 1000;<br>
-Â Â Â Â Â Â Â Â maxFrameDurationNsec = frameDurationsInfo->second.max().get<int64_t>() * 1000;<br>
-<br>
-Â Â Â Â Â Â Â Â /*<br>
-Â Â Â Â Â Â Â Â * Adjust the minimum frame duration to comply with Android<br>
-Â Â Â Â Â Â Â Â * requirements. The camera service mandates all preview/record<br>
-Â Â Â Â Â Â Â Â * streams to have a minimum frame duration < 33,366 milliseconds<br>
-Â Â Â Â Â Â Â Â * (see MAX_PREVIEW_RECORD_DURATION_NS in the camera service<br>
-Â Â Â Â Â Â Â Â * implementation).<br>
-Â Â Â Â Â Â Â Â *<br>
-Â Â Â Â Â Â Â Â * If we're close enough (+ 500 useconds) to that value, round<br>
-Â Â Â Â Â Â Â Â * the minimum frame duration of the camera to an accepted<br>
-Â Â Â Â Â Â Â Â * value.<br>
-Â Â Â Â Â Â Â Â */<br>
-Â Â Â Â Â Â Â Â static constexpr int64_t MAX_PREVIEW_RECORD_DURATION_NS = 1e9 / 29.97;<br>
-Â Â Â Â Â Â Â Â if (minFrameDurationNsec > MAX_PREVIEW_RECORD_DURATION_NS &&<br>
-Â Â Â Â Â Â Â Â Â Â minFrameDurationNsec < MAX_PREVIEW_RECORD_DURATION_NS + 500000)<br>
-Â Â Â Â Â Â Â Â Â Â Â Â minFrameDurationNsec = MAX_PREVIEW_RECORD_DURATION_NS - 1000;<br>
-<br>
-Â Â Â Â Â Â Â Â /*<br>
-Â Â Â Â Â Â Â Â * The AE routine frame rate limits are computed using the frame<br>
-Â Â Â Â Â Â Â Â * duration limits, as libcamera clips the AE routine to the<br>
-Â Â Â Â Â Â Â Â * frame durations.<br>
-Â Â Â Â Â Â Â Â */<br>
-Â Â Â Â Â Â Â Â int32_t maxFps = std::round(1e9 / minFrameDurationNsec);<br>
-Â Â Â Â Â Â Â Â int32_t minFps = std::round(1e9 / maxFrameDurationNsec);<br>
-Â Â Â Â Â Â Â Â minFps = std::max(1, minFps);<br>
-<br>
-Â Â Â Â Â Â Â Â /*<br>
-Â Â Â Â Â Â Â Â * Force rounding errors so that we have the proper frame<br>
-Â Â Â Â Â Â Â Â * durations for when we reuse these variables later<br>
-Â Â Â Â Â Â Â Â */<br>
-Â Â Â Â Â Â Â Â minFrameDurationNsec = 1e9 / maxFps;<br>
-Â Â Â Â Â Â Â Â maxFrameDurationNsec = 1e9 / minFps;<br>
-<br>
-Â Â Â Â Â Â Â Â /*<br>
-Â Â Â Â Â Â Â Â * Register to the camera service {min, max} and {max, max}<br>
-Â Â Â Â Â Â Â Â * intervals as requested by the metadata documentation.<br>
-Â Â Â Â Â Â Â Â */<br>
-Â Â Â Â Â Â Â Â int32_t availableAeFpsTarget[] = {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â minFps, maxFps, maxFps, maxFps<br>
-Â Â Â Â Â Â Â Â };<br>
-Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableAeFpsTarget);<br>
-Â Â Â Â }<br>
-<br>
-Â Â Â Â std::vector<int32_t> aeCompensationRange = {<br>
-Â Â Â Â Â Â Â Â 0, 0,<br>
-Â Â Â Â };<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_RANGE,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â aeCompensationRange);<br>
-<br>
-Â Â Â Â const camera_metadata_rational_t aeCompensationStep[] = {<br>
-Â Â Â Â Â Â Â Â { 0, 1 }<br>
-Â Â Â Â };<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_STEP,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â aeCompensationStep);<br>
-<br>
-Â Â Â Â std::vector<uint8_t> availableAfModes = {<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AF_MODE_OFF,<br>
-Â Â Â Â };<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AF_AVAILABLE_MODES,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableAfModes);<br>
-<br>
-Â Â Â Â std::vector<uint8_t> availableEffects = {<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_EFFECT_MODE_OFF,<br>
-Â Â Â Â };<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_EFFECTS,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableEffects);<br>
-<br>
-Â Â Â Â std::vector<uint8_t> availableSceneModes = {<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_SCENE_MODE_DISABLED,<br>
-Â Â Â Â };<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_SCENE_MODES,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableSceneModes);<br>
-<br>
-Â Â Â Â std::vector<uint8_t> availableStabilizationModes = {<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF,<br>
-Â Â Â Â };<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableStabilizationModes);<br>
-<br>
-Â Â Â Â /*<br>
-Â Â Â Â * \todo Inspect the Camera capabilities to report the available<br>
-Â Â Â Â * AWB modes. Default to AUTO as CTS tests require it.<br>
-Â Â Â Â */<br>
-Â Â Â Â std::vector<uint8_t> availableAwbModes = {<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AWB_MODE_AUTO,<br>
-Â Â Â Â };<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AWB_AVAILABLE_MODES,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableAwbModes);<br>
-<br>
-Â Â Â Â std::vector<int32_t> availableMaxRegions = {<br>
-Â Â Â Â Â Â Â Â 0, 0, 0,<br>
-Â Â Â Â };<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_MAX_REGIONS,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableMaxRegions);<br>
-<br>
-Â Â Â Â std::vector<uint8_t> sceneModesOverride = {<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_MODE_ON,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AWB_MODE_AUTO,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AF_MODE_OFF,<br>
-Â Â Â Â };<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_SCENE_MODE_OVERRIDES,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sceneModesOverride);<br>
-<br>
-Â Â Â Â uint8_t aeLockAvailable = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE;<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â aeLockAvailable);<br>
-<br>
-Â Â Â Â uint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AWB_LOCK_AVAILABLE,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â awbLockAvailable);<br>
-<br>
-Â Â Â Â char availableControlModes = ANDROID_CONTROL_MODE_AUTO;<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_MODES,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableControlModes);<br>
-<br>
-Â Â Â Â /* JPEG static metadata. */<br>
-<br>
-Â Â Â Â /*<br>
-Â Â Â Â * Create the list of supported thumbnail sizes by inspecting the<br>
-Â Â Â Â * available JPEG resolutions collected in streamConfigurations_ and<br>
-Â Â Â Â * generate one entry for each aspect ratio.<br>
-Â Â Â Â *<br>
-Â Â Â Â * The JPEG thumbnailer can freely scale, so pick an arbitrary<br>
-Â Â Â Â * (160, 160) size as the bounding rectangle, which is then cropped to<br>
-Â Â Â Â * the different supported aspect ratios.<br>
-Â Â Â Â */<br>
-Â Â Â Â constexpr Size maxJpegThumbnail(160, 160);<br>
-Â Â Â Â std::vector<Size> thumbnailSizes;<br>
-Â Â Â Â thumbnailSizes.push_back({ 0, 0 });<br>
-Â Â Â Â for (const auto &entry : streamConfigurations_) {<br>
-Â Â Â Â Â Â Â Â if (entry.androidFormat != HAL_PIXEL_FORMAT_BLOB)<br>
-Â Â Â Â Â Â Â Â Â Â Â Â continue;<br>
-<br>
-Â Â Â Â Â Â Â Â Size thumbnailSize = maxJpegThumbnail<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â .boundedToAspectRatio({ entry.resolution.width,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â entry.resolution.height });<br>
-Â Â Â Â Â Â Â Â thumbnailSizes.push_back(thumbnailSize);<br>
-Â Â Â Â }<br>
-<br>
-Â Â Â Â std::sort(thumbnailSizes.begin(), thumbnailSizes.end());<br>
-Â Â Â Â auto last = std::unique(thumbnailSizes.begin(), thumbnailSizes.end());<br>
-Â Â Â Â thumbnailSizes.erase(last, thumbnailSizes.end());<br>
-<br>
-Â Â Â Â /* Transform sizes in to a list of integers that can be consumed. */<br>
-Â Â Â Â std::vector<int32_t> thumbnailEntries;<br>
-Â Â Â Â thumbnailEntries.reserve(thumbnailSizes.size() * 2);<br>
-Â Â Â Â for (const auto &size : thumbnailSizes) {<br>
-Â Â Â Â Â Â Â Â thumbnailEntries.push_back(size.width);<br>
-Â Â Â Â Â Â Â Â thumbnailEntries.push_back(size.height);<br>
-Â Â Â Â }<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â thumbnailEntries);<br>
-<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_JPEG_MAX_SIZE, maxJpegBufferSize_);<br>
-<br>
-Â Â Â Â /* Sensor static metadata. */<br>
-Â Â Â Â std::array<int32_t, 2> pixelArraySize;<br>
-Â Â Â Â {<br>
-Â Â Â Â Â Â Â Â const Size &size = properties.get(properties::PixelArraySize);<br>
-Â Â Â Â Â Â Â Â pixelArraySize[0] = size.width;<br>
-Â Â Â Â Â Â Â Â pixelArraySize[1] = size.height;<br>
-Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â pixelArraySize);<br>
-Â Â Â Â }<br>
-<br>
-Â Â Â Â if (properties.contains(properties::UnitCellSize)) {<br>
-Â Â Â Â Â Â Â Â const Size &cellSize = properties.get<Size>(properties::UnitCellSize);<br>
-Â Â Â Â Â Â Â Â std::array<float, 2> physicalSize{<br>
-Â Â Â Â Â Â Â Â Â Â Â Â cellSize.width * pixelArraySize[0] / 1e6f,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â cellSize.height * pixelArraySize[1] / 1e6f<br>
-Â Â Â Â Â Â Â Â };<br>
-Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â physicalSize);<br>
-Â Â Â Â }<br>
-<br>
-Â Â Â Â {<br>
-Â Â Â Â Â Â Â Â const Span<const Rectangle> &rects =<br>
-Â Â Â Â Â Â Â Â Â Â Â Â properties.get(properties::PixelArrayActiveAreas);<br>
-Â Â Â Â Â Â Â Â std::vector<int32_t> data{<br>
-Â Â Â Â Â Â Â Â Â Â Â Â static_cast<int32_t>(rects[0].x),<br>
-Â Â Â Â Â Â Â Â Â Â Â Â static_cast<int32_t>(rects[0].y),<br>
-Â Â Â Â Â Â Â Â Â Â Â Â static_cast<int32_t>(rects[0].width),<br>
-Â Â Â Â Â Â Â Â Â Â Â Â static_cast<int32_t>(rects[0].height),<br>
-Â Â Â Â Â Â Â Â };<br>
-Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â data);<br>
-Â Â Â Â }<br>
-<br>
-Â Â Â Â int32_t sensitivityRange[] = {<br>
-Â Â Â Â Â Â Â Â 32, 2400,<br>
-Â Â Â Â };<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â sensitivityRange);<br>
-<br>
-Â Â Â Â /* Report the color filter arrangement if the camera reports it. */<br>
-Â Â Â Â if (properties.contains(properties::draft::ColorFilterArrangement)) {<br>
-Â Â Â Â Â Â Â Â uint8_t filterArr = properties.get(properties::draft::ColorFilterArrangement);<br>
-Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â filterArr);<br>
-Â Â Â Â }<br>
-<br>
-Â Â Â Â const auto &exposureInfo = controlsInfo.find(&controls::ExposureTime);<br>
-Â Â Â Â if (exposureInfo != controlsInfo.end()) {<br>
-Â Â Â Â Â Â Â Â int64_t exposureTimeRange[2] = {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â exposureInfo->second.min().get<int32_t>() * 1000LL,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â exposureInfo->second.max().get<int32_t>() * 1000LL,<br>
-Â Â Â Â Â Â Â Â };<br>
-Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â exposureTimeRange, 2);<br>
-Â Â Â Â }<br>
-<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_SENSOR_ORIENTATION, orientation_);<br>
-<br>
-Â Â Â Â std::vector<int32_t> testPatternModes = {<br>
-Â Â Â Â Â Â Â Â ANDROID_SENSOR_TEST_PATTERN_MODE_OFF<br>
-Â Â Â Â };<br>
-Â Â Â Â const auto &testPatternsInfo =<br>
-Â Â Â Â Â Â Â Â controlsInfo.find(&controls::draft::TestPatternMode);<br>
-Â Â Â Â if (testPatternsInfo != controlsInfo.end()) {<br>
-Â Â Â Â Â Â Â Â const auto &values = testPatternsInfo->second.values();<br>
-Â Â Â Â Â Â Â Â ASSERT(!values.empty());<br>
-Â Â Â Â Â Â Â Â for (const auto &value : values) {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â switch (value.get<int32_t>()) {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â case controls::draft::TestPatternModeOff:<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â /*<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â * ANDROID_SENSOR_TEST_PATTERN_MODE_OFF is<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â * already in testPatternModes.<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â */<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;<br>
-<br>
-Â Â Â Â Â Â Â Â Â Â Â Â case controls::draft::TestPatternModeSolidColor:<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â testPatternModes.push_back(<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR);<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;<br>
-<br>
-Â Â Â Â Â Â Â Â Â Â Â Â case controls::draft::TestPatternModeColorBars:<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â testPatternModes.push_back(<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS);<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;<br>
-<br>
-Â Â Â Â Â Â Â Â Â Â Â Â case controls::draft::TestPatternModeColorBarsFadeToGray:<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â testPatternModes.push_back(<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY);<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;<br>
-<br>
-Â Â Â Â Â Â Â Â Â Â Â Â case controls::draft::TestPatternModePn9:<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â testPatternModes.push_back(<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â ANDROID_SENSOR_TEST_PATTERN_MODE_PN9);<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;<br>
-<br>
-Â Â Â Â Â Â Â Â Â Â Â Â case controls::draft::TestPatternModeCustom1:<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â /* We don't support this yet. */<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â break;<br>
-<br>
-Â Â Â Â Â Â Â Â Â Â Â Â default:<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â LOG(HAL, Error) << "Unknown test pattern mode: "<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << value.get<int32_t>();<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â continue;<br>
-Â Â Â Â Â Â Â Â Â Â Â Â }<br>
-Â Â Â Â Â Â Â Â }<br>
-Â Â Â Â }<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â testPatternModes);<br>
-<br>
-Â Â Â Â uint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â timestampSource);<br>
-<br>
-Â Â Â Â if (maxFrameDurationNsec > 0)<br>
-Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â maxFrameDurationNsec);<br>
-<br>
-Â Â Â Â /* Statistics static metadata. */<br>
-Â Â Â Â uint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â faceDetectMode);<br>
-<br>
-Â Â Â Â int32_t maxFaceCount = 0;<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â maxFaceCount);<br>
-<br>
-Â Â Â Â {<br>
-Â Â Â Â Â Â Â Â std::vector<uint8_t> data;<br>
-Â Â Â Â Â Â Â Â data.reserve(2);<br>
-Â Â Â Â Â Â Â Â const auto &infoMap = controlsInfo.find(&controls::draft::LensShadingMapMode);<br>
-Â Â Â Â Â Â Â Â if (infoMap != controlsInfo.end()) {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â for (const auto &value : infoMap->second.values())<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â data.push_back(value.get<int32_t>());<br>
-Â Â Â Â Â Â Â Â } else {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â data.push_back(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF);<br>
-Â Â Â Â Â Â Â Â }<br>
-Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â data);<br>
-Â Â Â Â }<br>
-<br>
-Â Â Â Â /* Sync static metadata. */<br>
-Â Â Â Â int32_t maxLatency = ANDROID_SYNC_MAX_LATENCY_UNKNOWN;<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_SYNC_MAX_LATENCY, maxLatency);<br>
-<br>
-Â Â Â Â /* Flash static metadata. */<br>
-Â Â Â Â char flashAvailable = ANDROID_FLASH_INFO_AVAILABLE_FALSE;<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_FLASH_INFO_AVAILABLE,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â flashAvailable);<br>
-<br>
-Â Â Â Â /* Lens static metadata. */<br>
-Â Â Â Â std::vector<float> lensApertures = {<br>
-Â Â Â Â Â Â Â Â 2.53 / 100,<br>
-Â Â Â Â };<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_APERTURES,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â lensApertures);<br>
-<br>
-Â Â Â Â uint8_t lensFacing;<br>
-Â Â Â Â switch (facing_) {<br>
-Â Â Â Â default:<br>
-Â Â Â Â case CAMERA_FACING_FRONT:<br>
-Â Â Â Â Â Â Â Â lensFacing = ANDROID_LENS_FACING_FRONT;<br>
-Â Â Â Â Â Â Â Â break;<br>
-Â Â Â Â case CAMERA_FACING_BACK:<br>
-Â Â Â Â Â Â Â Â lensFacing = ANDROID_LENS_FACING_BACK;<br>
-Â Â Â Â Â Â Â Â break;<br>
-Â Â Â Â case CAMERA_FACING_EXTERNAL:<br>
-Â Â Â Â Â Â Â Â lensFacing = ANDROID_LENS_FACING_EXTERNAL;<br>
-Â Â Â Â Â Â Â Â break;<br>
-Â Â Â Â }<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_LENS_FACING, lensFacing);<br>
-<br>
-Â Â Â Â std::vector<float> lensFocalLengths = {<br>
-Â Â Â Â Â Â Â Â 1,<br>
-Â Â Â Â };<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â lensFocalLengths);<br>
-<br>
-Â Â Â Â std::vector<uint8_t> opticalStabilizations = {<br>
-Â Â Â Â Â Â Â Â ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF,<br>
-Â Â Â Â };<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â opticalStabilizations);<br>
-<br>
-Â Â Â Â float hypeFocalDistance = 0;<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â hypeFocalDistance);<br>
-<br>
-Â Â Â Â float minFocusDistance = 0;<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â minFocusDistance);<br>
-<br>
-Â Â Â Â /* Noise reduction modes. */<br>
-Â Â Â Â {<br>
-Â Â Â Â Â Â Â Â std::vector<uint8_t> data;<br>
-Â Â Â Â Â Â Â Â data.reserve(5);<br>
-Â Â Â Â Â Â Â Â const auto &infoMap = controlsInfo.find(&controls::draft::NoiseReductionMode);<br>
-Â Â Â Â Â Â Â Â if (infoMap != controlsInfo.end()) {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â for (const auto &value : infoMap->second.values())<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â data.push_back(value.get<int32_t>());<br>
-Â Â Â Â Â Â Â Â } else {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â data.push_back(ANDROID_NOISE_REDUCTION_MODE_OFF);<br>
-Â Â Â Â Â Â Â Â }<br>
-Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â data);<br>
-Â Â Â Â }<br>
-<br>
-Â Â Â Â /* Scaler static metadata. */<br>
-<br>
-Â Â Â Â /*<br>
-Â Â Â Â * \todo The digital zoom factor is a property that depends on the<br>
-Â Â Â Â * desired output configuration and the sensor frame size input to the<br>
-Â Â Â Â * ISP. This information is not available to the Android HAL, not at<br>
-Â Â Â Â * initialization time at least.<br>
-Â Â Â Â *<br>
-Â Â Â Â * As a workaround rely on pipeline handlers initializing the<br>
-Â Â Â Â * ScalerCrop control with the camera default configuration and use the<br>
-Â Â Â Â * maximum and minimum crop rectangles to calculate the digital zoom<br>
-Â Â Â Â * factor.<br>
-Â Â Â Â */<br>
-Â Â Â Â float maxZoom = 1.0f;<br>
-Â Â Â Â const auto scalerCrop = controlsInfo.find(&controls::ScalerCrop);<br>
-Â Â Â Â if (scalerCrop != controlsInfo.end()) {<br>
-Â Â Â Â Â Â Â Â Rectangle min = scalerCrop->second.min().get<Rectangle>();<br>
-Â Â Â Â Â Â Â Â Rectangle max = scalerCrop->second.max().get<Rectangle>();<br>
-Â Â Â Â Â Â Â Â maxZoom = std::min(1.0f * max.width / min.width,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â 1.0f * max.height / min.height);<br>
-Â Â Â Â }<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â maxZoom);<br>
-<br>
-Â Â Â Â std::vector<uint32_t> availableStreamConfigurations;<br>
-Â Â Â Â availableStreamConfigurations.reserve(streamConfigurations_.size() * 4);<br>
-Â Â Â Â for (const auto &entry : streamConfigurations_) {<br>
-Â Â Â Â Â Â Â Â availableStreamConfigurations.push_back(entry.androidFormat);<br>
-Â Â Â Â Â Â Â Â availableStreamConfigurations.push_back(entry.resolution.width);<br>
-Â Â Â Â Â Â Â Â availableStreamConfigurations.push_back(entry.resolution.height);<br>
-Â Â Â Â Â Â Â Â availableStreamConfigurations.push_back(<br>
-Â Â Â Â Â Â Â Â Â Â Â Â ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);<br>
-Â Â Â Â }<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableStreamConfigurations);<br>
-<br>
-Â Â Â Â std::vector<int64_t> availableStallDurations = {<br>
-Â Â Â Â Â Â Â Â ANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920, 33333333,<br>
-Â Â Â Â };<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableStallDurations);<br>
-<br>
-Â Â Â Â /* Use the minimum frame duration for all the YUV/RGB formats. */<br>
-Â Â Â Â if (minFrameDurationNsec > 0) {<br>
-Â Â Â Â Â Â Â Â std::vector<int64_t> minFrameDurations;<br>
-Â Â Â Â Â Â Â Â minFrameDurations.reserve(streamConfigurations_.size() * 4);<br>
-Â Â Â Â Â Â Â Â for (const auto &entry : streamConfigurations_) {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â minFrameDurations.push_back(entry.androidFormat);<br>
-Â Â Â Â Â Â Â Â Â Â Â Â minFrameDurations.push_back(entry.resolution.width);<br>
-Â Â Â Â Â Â Â Â Â Â Â Â minFrameDurations.push_back(entry.resolution.height);<br>
-Â Â Â Â Â Â Â Â Â Â Â Â minFrameDurations.push_back(minFrameDurationNsec);<br>
-Â Â Â Â Â Â Â Â }<br>
-Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â minFrameDurations);<br>
-Â Â Â Â }<br>
-<br>
-Â Â Â Â uint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY;<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_SCALER_CROPPING_TYPE, croppingType);<br>
-<br>
-Â Â Â Â /* Info static metadata. */<br>
-Â Â Â Â uint8_t supportedHWLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â supportedHWLevel);<br>
-<br>
-Â Â Â Â /* Request static metadata. */<br>
-Â Â Â Â int32_t partialResultCount = 1;<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_REQUEST_PARTIAL_RESULT_COUNT,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â partialResultCount);<br>
-<br>
-Â Â Â Â {<br>
-Â Â Â Â Â Â Â Â /* Default the value to 2 if not reported by the camera. */<br>
-Â Â Â Â Â Â Â Â uint8_t maxPipelineDepth = 2;<br>
-Â Â Â Â Â Â Â Â const auto &infoMap = controlsInfo.find(&controls::draft::PipelineDepth);<br>
-Â Â Â Â Â Â Â Â if (infoMap != controlsInfo.end())<br>
-Â Â Â Â Â Â Â Â Â Â Â Â maxPipelineDepth = infoMap->second.max().get<int32_t>();<br>
-Â Â Â Â Â Â Â Â staticMetadata_->addEntry(ANDROID_REQUEST_PIPELINE_MAX_DEPTH,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â maxPipelineDepth);<br>
-Â Â Â Â }<br>
-<br>
-Â Â Â Â /* LIMITED does not support reprocessing. */<br>
-Â Â Â Â uint32_t maxNumInputStreams = 0;<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â maxNumInputStreams);<br>
-<br>
-Â Â Â Â std::vector<uint8_t> availableCapabilities = {<br>
-Â Â Â Â Â Â Â Â ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,<br>
-Â Â Â Â };<br>
-<br>
-Â Â Â Â /* Report if camera supports RAW. */<br>
-Â Â Â Â bool rawStreamAvailable = false;<br>
-Â Â Â Â std::unique_ptr<CameraConfiguration> cameraConfig =<br>
-Â Â Â Â Â Â Â Â camera_->generateConfiguration({ StreamRole::Raw });<br>
-Â Â Â Â if (cameraConfig && !cameraConfig->empty()) {<br>
-Â Â Â Â Â Â Â Â const PixelFormatInfo &info =<br>
-Â Â Â Â Â Â Â Â Â Â Â Â PixelFormatInfo::info(cameraConfig->at(0).pixelFormat);<br>
-Â Â Â Â Â Â Â Â /* Only advertise RAW support if RAW16 is possible. */<br>
-Â Â Â Â Â Â Â Â if (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW &&<br>
-Â Â Â Â Â Â Â Â Â Â info.bitsPerPixel == 16) {<br>
-Â Â Â Â Â Â Â Â Â Â Â Â rawStreamAvailable = true;<br>
-Â Â Â Â Â Â Â Â Â Â Â Â availableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);<br>
-Â Â Â Â Â Â Â Â }<br>
-Â Â Â Â }<br>
-<br>
-Â Â Â Â /* Number of { RAW, YUV, JPEG } supported output streams */<br>
-Â Â Â Â int32_t numOutStreams[] = { rawStreamAvailable, 2, 1 };<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â numOutStreams);<br>
-<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CAPABILITIES,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableCapabilities);<br>
-<br>
-Â Â Â Â std::vector<int32_t> availableCharacteristicsKeys = {<br>
-Â Â Â Â Â Â Â Â ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_AVAILABLE_MODES,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_COMPENSATION_RANGE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_COMPENSATION_STEP,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_LOCK_AVAILABLE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AF_AVAILABLE_MODES,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AVAILABLE_EFFECTS,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AVAILABLE_MODES,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AVAILABLE_SCENE_MODES,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AWB_AVAILABLE_MODES,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AWB_LOCK_AVAILABLE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_MAX_REGIONS,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_SCENE_MODE_OVERRIDES,<br>
-Â Â Â Â Â Â Â Â ANDROID_FLASH_INFO_AVAILABLE,<br>
-Â Â Â Â Â Â Â Â ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,<br>
-Â Â Â Â Â Â Â Â ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,<br>
-Â Â Â Â Â Â Â Â ANDROID_JPEG_MAX_SIZE,<br>
-Â Â Â Â Â Â Â Â ANDROID_LENS_FACING,<br>
-Â Â Â Â Â Â Â Â ANDROID_LENS_INFO_AVAILABLE_APERTURES,<br>
-Â Â Â Â Â Â Â Â ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,<br>
-Â Â Â Â Â Â Â Â ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,<br>
-Â Â Â Â Â Â Â Â ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,<br>
-Â Â Â Â Â Â Â Â ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,<br>
-Â Â Â Â Â Â Â Â ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,<br>
-Â Â Â Â Â Â Â Â ANDROID_REQUEST_AVAILABLE_CAPABILITIES,<br>
-Â Â Â Â Â Â Â Â ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,<br>
-Â Â Â Â Â Â Â Â ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,<br>
-Â Â Â Â Â Â Â Â ANDROID_REQUEST_PARTIAL_RESULT_COUNT,<br>
-Â Â Â Â Â Â Â Â ANDROID_REQUEST_PIPELINE_MAX_DEPTH,<br>
-Â Â Â Â Â Â Â Â ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,<br>
-Â Â Â Â Â Â Â Â ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,<br>
-Â Â Â Â Â Â Â Â ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,<br>
-Â Â Â Â Â Â Â Â ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,<br>
-Â Â Â Â Â Â Â Â ANDROID_SCALER_CROPPING_TYPE,<br>
-Â Â Â Â Â Â Â Â ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,<br>
-Â Â Â Â Â Â Â Â ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,<br>
-Â Â Â Â Â Â Â Â ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,<br>
-Â Â Â Â Â Â Â Â ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,<br>
-Â Â Â Â Â Â Â Â ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,<br>
-Â Â Â Â Â Â Â Â ANDROID_SENSOR_INFO_PHYSICAL_SIZE,<br>
-Â Â Â Â Â Â Â Â ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,<br>
-Â Â Â Â Â Â Â Â ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,<br>
-Â Â Â Â Â Â Â Â ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,<br>
-Â Â Â Â Â Â Â Â ANDROID_SENSOR_ORIENTATION,<br>
-Â Â Â Â Â Â Â Â ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,<br>
-Â Â Â Â Â Â Â Â ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,<br>
-Â Â Â Â Â Â Â Â ANDROID_SYNC_MAX_LATENCY,<br>
-Â Â Â Â };<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableCharacteristicsKeys);<br>
-<br>
-Â Â Â Â std::vector<int32_t> availableRequestKeys = {<br>
-Â Â Â Â Â Â Â Â ANDROID_COLOR_CORRECTION_ABERRATION_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_ANTIBANDING_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_LOCK,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_TARGET_FPS_RANGE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AF_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AF_TRIGGER,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AWB_LOCK,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AWB_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_CAPTURE_INTENT,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_EFFECT_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_SCENE_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_FLASH_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_JPEG_ORIENTATION,<br>
-Â Â Â Â Â Â Â Â ANDROID_JPEG_QUALITY,<br>
-Â Â Â Â Â Â Â Â ANDROID_JPEG_THUMBNAIL_QUALITY,<br>
-Â Â Â Â Â Â Â Â ANDROID_JPEG_THUMBNAIL_SIZE,<br>
-Â Â Â Â Â Â Â Â ANDROID_LENS_APERTURE,<br>
-Â Â Â Â Â Â Â Â ANDROID_LENS_OPTICAL_STABILIZATION_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_NOISE_REDUCTION_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_SCALER_CROP_REGION,<br>
-Â Â Â Â Â Â Â Â ANDROID_STATISTICS_FACE_DETECT_MODE<br>
-Â Â Â Â };<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableRequestKeys);<br>
-<br>
-Â Â Â Â std::vector<int32_t> availableResultKeys = {<br>
-Â Â Â Â Â Â Â Â ANDROID_COLOR_CORRECTION_ABERRATION_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_ANTIBANDING_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_LOCK,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_STATE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AE_TARGET_FPS_RANGE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AF_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AF_STATE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AF_TRIGGER,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AWB_LOCK,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AWB_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_AWB_STATE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_CAPTURE_INTENT,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_EFFECT_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_SCENE_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_CONTROL_VIDEO_STABILIZATION_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_FLASH_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_FLASH_STATE,<br>
-Â Â Â Â Â Â Â Â ANDROID_JPEG_GPS_COORDINATES,<br>
-Â Â Â Â Â Â Â Â ANDROID_JPEG_GPS_PROCESSING_METHOD,<br>
-Â Â Â Â Â Â Â Â ANDROID_JPEG_GPS_TIMESTAMP,<br>
-Â Â Â Â Â Â Â Â ANDROID_JPEG_ORIENTATION,<br>
-Â Â Â Â Â Â Â Â ANDROID_JPEG_QUALITY,<br>
-Â Â Â Â Â Â Â Â ANDROID_JPEG_SIZE,<br>
-Â Â Â Â Â Â Â Â ANDROID_JPEG_THUMBNAIL_QUALITY,<br>
-Â Â Â Â Â Â Â Â ANDROID_JPEG_THUMBNAIL_SIZE,<br>
-Â Â Â Â Â Â Â Â ANDROID_LENS_APERTURE,<br>
-Â Â Â Â Â Â Â Â ANDROID_LENS_FOCAL_LENGTH,<br>
-Â Â Â Â Â Â Â Â ANDROID_LENS_OPTICAL_STABILIZATION_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_LENS_STATE,<br>
-Â Â Â Â Â Â Â Â ANDROID_NOISE_REDUCTION_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_REQUEST_PIPELINE_DEPTH,<br>
-Â Â Â Â Â Â Â Â ANDROID_SCALER_CROP_REGION,<br>
-Â Â Â Â Â Â Â Â ANDROID_SENSOR_EXPOSURE_TIME,<br>
-Â Â Â Â Â Â Â Â ANDROID_SENSOR_FRAME_DURATION,<br>
-Â Â Â Â Â Â Â Â ANDROID_SENSOR_ROLLING_SHUTTER_SKEW,<br>
-Â Â Â Â Â Â Â Â ANDROID_SENSOR_TEST_PATTERN_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_SENSOR_TIMESTAMP,<br>
-Â Â Â Â Â Â Â Â ANDROID_STATISTICS_FACE_DETECT_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_STATISTICS_LENS_SHADING_MAP_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,<br>
-Â Â Â Â Â Â Â Â ANDROID_STATISTICS_SCENE_FLICKER,<br>
-Â Â Â Â };<br>
-Â Â Â Â staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â availableResultKeys);<br>
-<br>
-Â Â Â Â if (!staticMetadata_->isValid()) {<br>
-Â Â Â Â Â Â Â Â LOG(HAL, Error) << "Failed to construct static metadata";<br>
-Â Â Â Â Â Â Â Â staticMetadata_.reset();<br>
-Â Â Â Â Â Â Â Â return nullptr;<br>
-Â Â Â Â }<br>
-<br>
-Â Â Â Â if (staticMetadata_->resized()) {<br>
-Â Â Â Â Â Â Â Â auto [entryCount, dataCount] = staticMetadata_->usage();<br>
-Â Â Â Â Â Â Â Â LOG(HAL, Info)<br>
-Â Â Â Â Â Â Â Â Â Â Â Â << "Static metadata resized: " << entryCount<br>
-Â Â Â Â Â Â Â Â Â Â Â Â << " entries and " << dataCount << " bytes used";<br>
-Â Â Â Â }<br>
-<br>
-Â Â Â Â return staticMetadata_->get();<br>
-}<br>
-<br>
-std::unique_ptr<CameraMetadata> CameraDevice::requestTemplatePreview()<br>
+void CameraDevice::setCallbacks(const camera3_callback_ops_t *callbacks)<br>
 {<br>
-Â Â Â Â /*<br>
-Â Â Â Â * \todo Keep this in sync with the actual number of entries.<br>
-Â Â Â Â * Currently: 20 entries, 35 bytes<br>
-Â Â Â Â */<br>
-Â Â Â Â auto requestTemplate = std::make_unique<CameraMetadata>(21, 36);<br>
-Â Â Â Â if (!requestTemplate->isValid()) {<br>
-Â Â Â Â Â Â Â Â return nullptr;<br>
-Â Â Â Â }<br>
-<br>
-Â Â Â Â /* Get the FPS range registered in the static metadata. */<br>
-Â Â Â Â camera_metadata_ro_entry_t entry;<br>
-Â Â Â Â bool found = staticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â &entry);<br>
-Â Â Â Â if (!found) {<br>
-Â Â Â Â Â Â Â Â LOG(HAL, Error) << "Cannot create capture template without FPS range";<br>
-Â Â Â Â Â Â Â Â return nullptr;<br>
-Â Â Â Â }<br>
-<br>
-Â Â Â Â /*<br>
-Â Â Â Â * Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata<br>
-Â Â Â Â * has been assembled as {{min, max} {max, max}}.<br>
-Â Â Â Â */<br>
-Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â entry.data.i32, 2);<br>
-<br>
-Â Â Â Â uint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;<br>
-Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_AE_MODE, aeMode);<br>
-<br>
-Â Â Â Â int32_t aeExposureCompensation = 0;<br>
-Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â aeExposureCompensation);<br>
-<br>
-Â Â Â Â uint8_t aePrecaptureTrigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;<br>
-Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â aePrecaptureTrigger);<br>
-<br>
-Â Â Â Â uint8_t aeLock = ANDROID_CONTROL_AE_LOCK_OFF;<br>
-Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_AE_LOCK, aeLock);<br>
-<br>
-Â Â Â Â uint8_t aeAntibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;<br>
-Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_AE_ANTIBANDING_MODE,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â aeAntibandingMode);<br>
-<br>
-Â Â Â Â uint8_t afMode = ANDROID_CONTROL_AF_MODE_OFF;<br>
-Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_AF_MODE, afMode);<br>
-<br>
-Â Â Â Â uint8_t afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;<br>
-Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_AF_TRIGGER, afTrigger);<br>
-<br>
-Â Â Â Â uint8_t awbMode = ANDROID_CONTROL_AWB_MODE_AUTO;<br>
-Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_AWB_MODE, awbMode);<br>
-<br>
-Â Â Â Â uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;<br>
-Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_AWB_LOCK, awbLock);<br>
-<br>
-Â Â Â Â uint8_t flashMode = ANDROID_FLASH_MODE_OFF;<br>
-Â Â Â Â requestTemplate->addEntry(ANDROID_FLASH_MODE, flashMode);<br>
-<br>
-Â Â Â Â uint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;<br>
-Â Â Â Â requestTemplate->addEntry(ANDROID_STATISTICS_FACE_DETECT_MODE,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â faceDetectMode);<br>
-<br>
-Â Â Â Â uint8_t noiseReduction = ANDROID_NOISE_REDUCTION_MODE_OFF;<br>
-Â Â Â Â requestTemplate->addEntry(ANDROID_NOISE_REDUCTION_MODE,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â noiseReduction);<br>
-<br>
-Â Â Â Â uint8_t aberrationMode = ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF;<br>
-Â Â Â Â requestTemplate->addEntry(ANDROID_COLOR_CORRECTION_ABERRATION_MODE,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â aberrationMode);<br>
-<br>
-Â Â Â Â uint8_t controlMode = ANDROID_CONTROL_MODE_AUTO;<br>
-Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_MODE, controlMode);<br>
-<br>
-Â Â Â Â float lensAperture = 2.53 / 100;<br>
-Â Â Â Â requestTemplate->addEntry(ANDROID_LENS_APERTURE, lensAperture);<br>
-<br>
-Â Â Â Â uint8_t opticalStabilization = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;<br>
-Â Â Â Â requestTemplate->addEntry(ANDROID_LENS_OPTICAL_STABILIZATION_MODE,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â opticalStabilization);<br>
-<br>
-Â Â Â Â uint8_t captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;<br>
-Â Â Â Â requestTemplate->addEntry(ANDROID_CONTROL_CAPTURE_INTENT,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â captureIntent);<br>
-<br>
-Â Â Â Â return requestTemplate;<br>
+Â Â Â Â callbacks_ = callbacks;<br>
 }<br>
<br>
-std::unique_ptr<CameraMetadata> CameraDevice::requestTemplateVideo()<br>
+const camera_metadata_t *CameraDevice::getStaticMetadata()<br>
 {<br>
-Â Â Â Â std::unique_ptr<CameraMetadata> previewTemplate = requestTemplatePreview();<br>
-Â Â Â Â if (!previewTemplate)<br>
-Â Â Â Â Â Â Â Â return nullptr;<br>
-<br>
-Â Â Â Â /*<br>
-Â Â Â Â * The video template requires a fixed FPS range. Everything else<br>
-Â Â Â Â * stays the same as the preview template.<br>
-Â Â Â Â */<br>
-Â Â Â Â camera_metadata_ro_entry_t entry;<br>
-Â Â Â Â staticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â &entry);<br>
-<br>
-Â Â Â Â /*<br>
-Â Â Â Â * Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata<br>
-Â Â Â Â * has been assembled as {{min, max} {max, max}}.<br>
-Â Â Â Â */<br>
-Â Â Â Â previewTemplate->updateEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â entry.data.i32 + 2, 2);<br>
-<br>
-Â Â Â Â return previewTemplate;<br>
+Â Â Â Â return capabilities_.staticMetadata()->get();<br>
 }<br>
<br>
 /*<br>
@@ -1630,7 +520,7 @@ const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type)<br>
    switch (type) {<br>
    case CAMERA3_TEMPLATE_PREVIEW:<br>
        captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;<br>
-Â Â Â Â Â Â Â Â requestTemplate = requestTemplatePreview();<br>
+Â Â Â Â Â Â Â Â requestTemplate = capabilities_.requestTemplatePreview();<br>
        break;<br>
    case CAMERA3_TEMPLATE_STILL_CAPTURE:<br>
        /*<br>
@@ -1638,15 +528,15 @@ const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type)<br>
         * for the torch mode we currently do not support.<br>
         */<br>
        captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;<br>
-Â Â Â Â Â Â Â Â requestTemplate = requestTemplatePreview();<br>
+Â Â Â Â Â Â Â Â requestTemplate = capabilities_.requestTemplatePreview();<br>
        break;<br>
    case CAMERA3_TEMPLATE_VIDEO_RECORD:<br>
        captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;<br>
-Â Â Â Â Â Â Â Â requestTemplate = requestTemplateVideo();<br>
+Â Â Â Â Â Â Â Â requestTemplate = capabilities_.requestTemplateVideo();<br>
        break;<br>
    case CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:<br>
        captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;<br>
-Â Â Â Â Â Â Â Â requestTemplate = requestTemplateVideo();<br>
+Â Â Â Â Â Â Â Â requestTemplate = capabilities_.requestTemplateVideo();<br>
        break;<br>
    /* \todo Implement templates generation for the remaining use cases. */<br>
    case CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:<br>
@@ -1668,19 +558,6 @@ const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type)<br>
    return requestTemplates_[type]->get();<br>
 }<br>
<br>
-PixelFormat CameraDevice::toPixelFormat(int format) const<br>
-{<br>
-Â Â Â Â /* Translate Android format code to libcamera pixel format. */<br>
-Â Â Â Â auto it = formatsMap_.find(format);<br>
-Â Â Â Â if (it == formatsMap_.end()) {<br>
-Â Â Â Â Â Â Â Â LOG(HAL, Error) << "Requested format " << utils::hex(format)<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â << " not supported";<br>
-Â Â Â Â Â Â Â Â return PixelFormat();<br>
-Â Â Â Â }<br>
-<br>
-Â Â Â Â return it->second;<br>
-}<br>
-<br>
 /*<br>
 * Inspect the stream_list to produce a list of StreamConfiguration to<br>
 * be use to configure the Camera.<br>
@@ -1727,7 +604,7 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)<br>
        camera3_stream_t *stream = stream_list->streams[i];<br>
        Size size(stream->width, stream->height);<br>
<br>
-Â Â Â Â Â Â Â Â PixelFormat format = toPixelFormat(stream->format);<br>
+Â Â Â Â Â Â Â Â PixelFormat format = capabilities_.toPixelFormat(stream->format);<br>
<br>
        LOG(HAL, Info) << "Stream #" << i<br>
                << ", direction: " << stream->stream_type<br>
diff --git a/src/android/camera_device.h b/src/android/camera_device.h<br>
index 4aadb27c562c..090fe28a551e 100644<br>
--- a/src/android/camera_device.h<br>
+++ b/src/android/camera_device.h<br>
@@ -10,14 +10,12 @@<br>
 #include <map><br>
 #include <memory><br>
 #include <mutex><br>
-#include <tuple><br>
 #include <vector><br>
<br>
 #include <hardware/camera3.h><br>
<br>
 #include <libcamera/buffer.h><br>
 #include <libcamera/camera.h><br>
-#include <libcamera/geometry.h><br>
 #include <libcamera/request.h><br>
 #include <libcamera/stream.h><br>
<br>
@@ -26,6 +24,7 @@<br>
 #include "libcamera/internal/message.h"<br>
 #include "libcamera/internal/thread.h"<br>
<br>
+#include "camera_capabilities.h"<br>
 #include "camera_metadata.h"<br>
 #include "camera_stream.h"<br>
 #include "camera_worker.h"<br>
@@ -57,7 +56,7 @@ public:<br>
    const std::string &model() const { return model_; }<br>
    int facing() const { return facing_; }<br>
    int orientation() const { return orientation_; }<br>
-Â Â Â Â unsigned int maxJpegBufferSize() const { return maxJpegBufferSize_; }<br>
+Â Â Â Â unsigned int maxJpegBufferSize() const;<br>
<br>
    void setCallbacks(const camera3_callback_ops_t *callbacks);<br>
    const camera_metadata_t *getStaticMetadata();<br>
@@ -86,11 +85,6 @@ private:<br>
        std::unique_ptr<CaptureRequest> request_;<br>
    };<br>
<br>
-Â Â Â Â struct Camera3StreamConfiguration {<br>
-Â Â Â Â Â Â Â Â libcamera::Size resolution;<br>
-Â Â Â Â Â Â Â Â int androidFormat;<br>
-Â Â Â Â };<br>
-<br>
    enum class State {<br>
        Stopped,<br>
        Flushing,<br>
@@ -99,22 +93,11 @@ private:<br>
<br>
    void stop();<br>
<br>
-Â Â Â Â int initializeStreamConfigurations();<br>
-Â Â Â Â std::vector<libcamera::Size><br>
-Â Â Â Â getYUVResolutions(libcamera::CameraConfiguration *cameraConfig,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â const libcamera::PixelFormat &pixelFormat,<br>
-Â Â Â Â Â Â Â Â Â Â Â Â Â const std::vector<libcamera::Size> &resolutions);<br>
-Â Â Â Â std::vector<libcamera::Size><br>
-Â Â Â Â getRawResolutions(const libcamera::PixelFormat &pixelFormat);<br>
-<br>
    libcamera::FrameBuffer *createFrameBuffer(const buffer_handle_t camera3buffer);<br>
    void abortRequest(camera3_capture_request_t *request);<br>
    void notifyShutter(uint32_t frameNumber, uint64_t timestamp);<br>
    void notifyError(uint32_t frameNumber, camera3_stream_t *stream,<br>
             camera3_error_msg_code code);<br>
-Â Â Â Â std::unique_ptr<CameraMetadata> requestTemplatePreview();<br>
-Â Â Â Â std::unique_ptr<CameraMetadata> requestTemplateVideo();<br>
-Â Â Â Â libcamera::PixelFormat toPixelFormat(int format) const;<br>
    int processControls(Camera3RequestDescriptor *descriptor);<br>
    std::unique_ptr<CameraMetadata> getResultMetadata(<br>
        const Camera3RequestDescriptor &descriptor) const;<br>
@@ -129,13 +112,11 @@ private:<br>
<br>
    std::shared_ptr<libcamera::Camera> camera_;<br>
    std::unique_ptr<libcamera::CameraConfiguration> config_;<br>
+Â Â Â Â CameraCapabilities capabilities_;<br>
<br>
-Â Â Â Â std::unique_ptr<CameraMetadata> staticMetadata_;<br>
    std::map<unsigned int, std::unique_ptr<CameraMetadata>> requestTemplates_;<br>
    const camera3_callback_ops_t *callbacks_;<br>
<br>
-Â Â Â Â std::vector<Camera3StreamConfiguration> streamConfigurations_;<br>
-Â Â Â Â std::map<int, libcamera::PixelFormat> formatsMap_;<br>
    std::vector<CameraStream> streams_;<br>
<br>
    libcamera::Mutex descriptorsMutex_; /* Protects descriptors_. */<br>
@@ -147,8 +128,6 @@ private:<br>
    int facing_;<br>
    int orientation_;<br>
<br>
-Â Â Â Â unsigned int maxJpegBufferSize_;<br>
-<br>
    CameraMetadata lastSettings_;<br>
 };<br>
<br>
diff --git a/src/android/meson.build b/src/android/meson.build<br>
index f27fd5316705..6270fb201338 100644<br>
--- a/src/android/meson.build<br>
+++ b/src/android/meson.build<br>
@@ -44,6 +44,7 @@ subdir('cros')<br>
<br>
 android_hal_sources = files([<br>
   'camera3_hal.cpp',<br>
+Â Â 'camera_capabilities.cpp',<br>
   'camera_device.cpp',<br>
   'camera_hal_config.cpp',<br>
   'camera_hal_manager.cpp',<br>
-- <br>
2.31.1<br>
<br>
</blockquote></div></div></div>