<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>