[{"id":17645,"web_url":"https://patchwork.libcamera.org/comment/17645/","msgid":"<YM6V63Kmy3/2zU/Y@pendragon.ideasonboard.com>","date":"2021-06-20T01:12:11","subject":"Re: [libcamera-devel] [RFC 1/1] android: Introduce\n\tCameraCapabilties class","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Jacopo,\n\nThank you for the patch.\n\nOn Sat, Jun 19, 2021 at 12:51:51PM +0200, Jacopo Mondi wrote:\n> The camera_device.cpp has grown a little too much, and it has quickly\n> become hard to maintain. Break out the handling of the static\n> information collected at camera initialization time to a new\n> CameraCapabilities class.\n> \n> Break out from the camera_device.cpp file all the functions relative to:\n> - Initialization of supported stream configurations\n> - Initialization of static metadata\n> - Initialization of request templates\n> \n> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n> ---\n>  src/android/camera_capabilities.cpp | 1165 +++++++++++++++++++++++++++\n>  src/android/camera_capabilities.h   |   64 ++\n>  src/android/camera_device.cpp       | 1147 +-------------------------\n>  src/android/camera_device.h         |   27 +-\n>  src/android/meson.build             |    1 +\n>  5 files changed, 1245 insertions(+), 1159 deletions(-)\n>  create mode 100644 src/android/camera_capabilities.cpp\n>  create mode 100644 src/android/camera_capabilities.h\n> \n> diff --git a/src/android/camera_capabilities.cpp b/src/android/camera_capabilities.cpp\n> new file mode 100644\n> index 000000000000..20df9a6f1abb\n> --- /dev/null\n> +++ b/src/android/camera_capabilities.cpp\n> @@ -0,0 +1,1165 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2021, Google Inc.\n> + *\n> + * camera_capabilities.cpp - Camera static properties manager\n> + */\n> +\n> +#include \"camera_capabilities.h\"\n> +\n> +#include <array>\n> +#include <cmath>\n> +\n> +#include <hardware/camera3.h>\n> +\n> +#include <libcamera/control_ids.h>\n> +#include <libcamera/controls.h>\n> +#include <libcamera/formats.h>\n> +#include <libcamera/property_ids.h>\n> +\n> +#include \"libcamera/internal/formats.h\"\n> +#include \"libcamera/internal/log.h\"\n> +\n> +using namespace libcamera;\n> +\n> +LOG_DECLARE_CATEGORY(HAL)\n> +\n> +namespace {\n> +\n> +/*\n> + * \\var camera3Resolutions\n> + * \\brief The list of image resolutions defined as mandatory to be supported by\n> + * the Android Camera3 specification\n> + */\n> +const std::vector<Size> camera3Resolutions = {\n> +\t{ 320, 240 },\n> +\t{ 640, 480 },\n> +\t{ 1280, 720 },\n> +\t{ 1920, 1080 }\n> +};\n> +\n> +/*\n> + * \\struct Camera3Format\n> + * \\brief Data associated with an Android format identifier\n> + * \\var libcameraFormats List of libcamera pixel formats compatible with the\n> + * Android format\n> + * \\var name The human-readable representation of the Android format code\n> + */\n> +struct Camera3Format {\n> +\tstd::vector<PixelFormat> libcameraFormats;\n> +\tbool mandatory;\n> +\tconst char *name;\n> +};\n> +\n> +/*\n> + * \\var camera3FormatsMap\n> + * \\brief Associate Android format code with ancillary data\n> + */\n> +const std::map<int, const Camera3Format> camera3FormatsMap = {\n> +\t{\n> +\t\tHAL_PIXEL_FORMAT_BLOB, {\n> +\t\t\t{ formats::MJPEG },\n> +\t\t\ttrue,\n> +\t\t\t\"BLOB\"\n> +\t\t}\n> +\t}, {\n> +\t\tHAL_PIXEL_FORMAT_YCbCr_420_888, {\n> +\t\t\t{ formats::NV12, formats::NV21 },\n> +\t\t\ttrue,\n> +\t\t\t\"YCbCr_420_888\"\n> +\t\t}\n> +\t}, {\n> +\t\t/*\n> +\t\t * \\todo Translate IMPLEMENTATION_DEFINED inspecting the gralloc\n> +\t\t * usage flag. For now, copy the YCbCr_420 configuration.\n> +\t\t */\n> +\t\tHAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, {\n> +\t\t\t{ formats::NV12, formats::NV21 },\n> +\t\t\ttrue,\n> +\t\t\t\"IMPLEMENTATION_DEFINED\"\n> +\t\t}\n> +\t}, {\n> +\t\tHAL_PIXEL_FORMAT_RAW10, {\n> +\t\t\t{\n> +\t\t\t\tformats::SBGGR10_CSI2P,\n> +\t\t\t\tformats::SGBRG10_CSI2P,\n> +\t\t\t\tformats::SGRBG10_CSI2P,\n> +\t\t\t\tformats::SRGGB10_CSI2P\n> +\t\t\t},\n> +\t\t\tfalse,\n> +\t\t\t\"RAW10\"\n> +\t\t}\n> +\t}, {\n> +\t\tHAL_PIXEL_FORMAT_RAW12, {\n> +\t\t\t{\n> +\t\t\t\tformats::SBGGR12_CSI2P,\n> +\t\t\t\tformats::SGBRG12_CSI2P,\n> +\t\t\t\tformats::SGRBG12_CSI2P,\n> +\t\t\t\tformats::SRGGB12_CSI2P\n> +\t\t\t},\n> +\t\t\tfalse,\n> +\t\t\t\"RAW12\"\n> +\t\t}\n> +\t}, {\n> +\t\tHAL_PIXEL_FORMAT_RAW16, {\n> +\t\t\t{\n> +\t\t\t\tformats::SBGGR16,\n> +\t\t\t\tformats::SGBRG16,\n> +\t\t\t\tformats::SGRBG16,\n> +\t\t\t\tformats::SRGGB16\n> +\t\t\t},\n> +\t\t\tfalse,\n> +\t\t\t\"RAW16\"\n> +\t\t}\n> +\t},\n> +};\n> +\n> +} /* namespace */\n> +\n> +int CameraCapabilities::initialize(std::shared_ptr<libcamera::Camera> camera,\n> +\t\t\t\t   int orientation, int facing)\n> +{\n> +\tcamera_ = camera;\n> +\torientation_ = orientation;\n> +\tfacing_ = facing;\n> +\n> +\t/* Acquire the camera and initialize available stream configurations. */\n> +\tint ret = camera_->acquire();\n> +\tif (ret) {\n> +\t\tLOG(HAL, Error) << \"Failed to temporarily acquire the camera\";\n> +\t\treturn ret;\n> +\t}\n> +\n> +\tret = initializeStreamConfigurations();\n> +\tcamera_->release();\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\treturn initializeStaticMetadata();\n> +}\n> +\n> +std::vector<Size> CameraCapabilities::getYUVResolutions(CameraConfiguration *cameraConfig,\n> +\t\t\t\t\t\t\tconst PixelFormat &pixelFormat,\n> +\t\t\t\t\t\t\tconst std::vector<Size> &resolutions)\n> +{\n> +\tstd::vector<Size> supportedResolutions;\n> +\n> +\tStreamConfiguration &cfg = cameraConfig->at(0);\n> +\tfor (const Size &res : resolutions) {\n> +\t\tcfg.pixelFormat = pixelFormat;\n> +\t\tcfg.size = res;\n> +\n> +\t\tCameraConfiguration::Status status = cameraConfig->validate();\n> +\t\tif (status != CameraConfiguration::Valid) {\n> +\t\t\tLOG(HAL, Debug) << cfg.toString() << \" not supported\";\n> +\t\t\tcontinue;\n> +\t\t}\n> +\n> +\t\tLOG(HAL, Debug) << cfg.toString() << \" supported\";\n> +\n> +\t\tsupportedResolutions.push_back(res);\n> +\t}\n> +\n> +\treturn supportedResolutions;\n> +}\n> +\n> +std::vector<Size> CameraCapabilities::getRawResolutions(const libcamera::PixelFormat &pixelFormat)\n> +{\n> +\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> +\t\tcamera_->generateConfiguration({ StreamRole::Raw });\n> +\tStreamConfiguration &cfg = cameraConfig->at(0);\n> +\tconst StreamFormats &formats = cfg.formats();\n> +\tstd::vector<Size> supportedResolutions = formats.sizes(pixelFormat);\n> +\n> +\treturn supportedResolutions;\n> +}\n> +\n> +/*\n> + * Initialize the format conversion map to translate from Android format\n> + * identifier to libcamera pixel formats and fill in the list of supported\n> + * stream configurations to be reported to the Android camera framework through\n> + * the Camera static metadata.\n> + */\n> +int CameraCapabilities::initializeStreamConfigurations()\n> +{\n> +\t/*\n> +\t * Get the maximum output resolutions\n> +\t * \\todo Get this from the camera properties once defined\n> +\t */\n> +\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> +\t\tcamera_->generateConfiguration({ StillCapture });\n> +\tif (!cameraConfig) {\n> +\t\tLOG(HAL, Error) << \"Failed to get maximum resolution\";\n> +\t\treturn -EINVAL;\n> +\t}\n> +\tStreamConfiguration &cfg = cameraConfig->at(0);\n> +\n> +\t/*\n> +\t * \\todo JPEG - Adjust the maximum available resolution by taking the\n> +\t * JPEG encoder requirements into account (alignment and aspect ratio).\n> +\t */\n> +\tconst Size maxRes = cfg.size;\n> +\tLOG(HAL, Debug) << \"Maximum supported resolution: \" << maxRes.toString();\n> +\n> +\t/*\n> +\t * Build the list of supported image resolutions.\n> +\t *\n> +\t * The resolutions listed in camera3Resolution are mandatory to be\n> +\t * supported, up to the camera maximum resolution.\n> +\t *\n> +\t * Augment the list by adding resolutions calculated from the camera\n> +\t * maximum one.\n> +\t */\n> +\tstd::vector<Size> cameraResolutions;\n> +\tstd::copy_if(camera3Resolutions.begin(), camera3Resolutions.end(),\n> +\t\t     std::back_inserter(cameraResolutions),\n> +\t\t     [&](const Size &res) { return res < maxRes; });\n> +\n> +\t/*\n> +\t * The Camera3 specification suggests adding 1/2 and 1/4 of the maximum\n> +\t * resolution.\n> +\t */\n> +\tfor (unsigned int divider = 2;; divider <<= 1) {\n> +\t\tSize derivedSize{\n> +\t\t\tmaxRes.width / divider,\n> +\t\t\tmaxRes.height / divider,\n> +\t\t};\n> +\n> +\t\tif (derivedSize.width < 320 ||\n> +\t\t    derivedSize.height < 240)\n> +\t\t\tbreak;\n> +\n> +\t\tcameraResolutions.push_back(derivedSize);\n> +\t}\n> +\tcameraResolutions.push_back(maxRes);\n> +\n> +\t/* Remove duplicated entries from the list of supported resolutions. */\n> +\tstd::sort(cameraResolutions.begin(), cameraResolutions.end());\n> +\tauto last = std::unique(cameraResolutions.begin(), cameraResolutions.end());\n> +\tcameraResolutions.erase(last, cameraResolutions.end());\n> +\n> +\t/*\n> +\t * Build the list of supported camera formats.\n> +\t *\n> +\t * To each Android format a list of compatible libcamera formats is\n> +\t * associated. The first libcamera format that tests successful is added\n> +\t * to the format translation map used when configuring the streams.\n> +\t * It is then tested against the list of supported camera resolutions to\n> +\t * build the stream configuration map reported through the camera static\n> +\t * metadata.\n> +\t */\n> +\tSize maxJpegSize;\n> +\tfor (const auto &format : camera3FormatsMap) {\n> +\t\tint androidFormat = format.first;\n> +\t\tconst Camera3Format &camera3Format = format.second;\n> +\t\tconst std::vector<PixelFormat> &libcameraFormats =\n> +\t\t\tcamera3Format.libcameraFormats;\n> +\n> +\t\tLOG(HAL, Debug) << \"Trying to map Android format \"\n> +\t\t\t\t<< camera3Format.name;\n> +\n> +\t\t/*\n> +\t\t * JPEG is always supported, either produced directly by the\n> +\t\t * camera, or encoded in the HAL.\n> +\t\t */\n> +\t\tif (androidFormat == HAL_PIXEL_FORMAT_BLOB) {\n> +\t\t\tformatsMap_[androidFormat] = formats::MJPEG;\n> +\t\t\tLOG(HAL, Debug) << \"Mapped Android format \"\n> +\t\t\t\t\t<< camera3Format.name << \" to \"\n> +\t\t\t\t\t<< formats::MJPEG.toString()\n> +\t\t\t\t\t<< \" (fixed mapping)\";\n> +\t\t\tcontinue;\n> +\t\t}\n> +\n> +\t\t/*\n> +\t\t * Test the libcamera formats that can produce images\n> +\t\t * compatible with the format defined by Android.\n> +\t\t */\n> +\t\tPixelFormat mappedFormat;\n> +\t\tfor (const PixelFormat &pixelFormat : libcameraFormats) {\n> +\n> +\t\t\tLOG(HAL, Debug) << \"Testing \" << pixelFormat.toString();\n> +\n> +\t\t\t/*\n> +\t\t\t * The stream configuration size can be adjusted,\n> +\t\t\t * not the pixel format.\n> +\t\t\t *\n> +\t\t\t * \\todo This could be simplified once all pipeline\n> +\t\t\t * handlers will report the StreamFormats list of\n> +\t\t\t * supported formats.\n> +\t\t\t */\n> +\t\t\tcfg.pixelFormat = pixelFormat;\n> +\n> +\t\t\tCameraConfiguration::Status status = cameraConfig->validate();\n> +\t\t\tif (status != CameraConfiguration::Invalid &&\n> +\t\t\t    cfg.pixelFormat == pixelFormat) {\n> +\t\t\t\tmappedFormat = pixelFormat;\n> +\t\t\t\tbreak;\n> +\t\t\t}\n> +\t\t}\n> +\n> +\t\tif (!mappedFormat.isValid()) {\n> +\t\t\t/* If the format is not mandatory, skip it. */\n> +\t\t\tif (!camera3Format.mandatory)\n> +\t\t\t\tcontinue;\n> +\n> +\t\t\tLOG(HAL, Error)\n> +\t\t\t\t<< \"Failed to map mandatory Android format \"\n> +\t\t\t\t<< camera3Format.name << \" (\"\n> +\t\t\t\t<< utils::hex(androidFormat) << \"): aborting\";\n> +\t\t\treturn -EINVAL;\n> +\t\t}\n> +\n> +\t\t/*\n> +\t\t * Record the mapping and then proceed to generate the\n> +\t\t * stream configurations map, by testing the image resolutions.\n> +\t\t */\n> +\t\tformatsMap_[androidFormat] = mappedFormat;\n> +\t\tLOG(HAL, Debug) << \"Mapped Android format \"\n> +\t\t\t\t<< camera3Format.name << \" to \"\n> +\t\t\t\t<< mappedFormat.toString();\n> +\n> +\t\tstd::vector<Size> resolutions;\n> +\t\tconst PixelFormatInfo &info = PixelFormatInfo::info(mappedFormat);\n> +\t\tif (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW)\n> +\t\t\tresolutions = getRawResolutions(mappedFormat);\n> +\t\telse\n> +\t\t\tresolutions = getYUVResolutions(cameraConfig.get(),\n> +\t\t\t\t\t\t\tmappedFormat,\n> +\t\t\t\t\t\t\tcameraResolutions);\n> +\n> +\t\tfor (const Size &res : resolutions) {\n> +\t\t\tstreamConfigurations_.push_back({ res, androidFormat });\n> +\n> +\t\t\t/*\n> +\t\t\t * If the format is HAL_PIXEL_FORMAT_YCbCr_420_888\n> +\t\t\t * from which JPEG is produced, add an entry for\n> +\t\t\t * the JPEG stream.\n> +\t\t\t *\n> +\t\t\t * \\todo Wire the JPEG encoder to query the supported\n> +\t\t\t * sizes provided a list of formats it can encode.\n> +\t\t\t *\n> +\t\t\t * \\todo Support JPEG streams produced by the Camera\n> +\t\t\t * natively.\n> +\t\t\t */\n> +\t\t\tif (androidFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {\n> +\t\t\t\tstreamConfigurations_.push_back(\n> +\t\t\t\t\t{ res, HAL_PIXEL_FORMAT_BLOB });\n> +\t\t\t\tmaxJpegSize = std::max(maxJpegSize, res);\n> +\t\t\t}\n> +\t\t}\n> +\n> +\t\t/*\n> +\t\t * \\todo Calculate the maximum JPEG buffer size by asking the\n> +\t\t * encoder giving the maximum frame size required.\n> +\t\t */\n> +\t\tmaxJpegBufferSize_ = maxJpegSize.width * maxJpegSize.height * 1.5;\n> +\t}\n> +\n> +\tLOG(HAL, Debug) << \"Collected stream configuration map: \";\n> +\tfor (const auto &entry : streamConfigurations_)\n> +\t\tLOG(HAL, Debug) << \"{ \" << entry.resolution.toString() << \" - \"\n> +\t\t\t\t<< utils::hex(entry.androidFormat) << \" }\";\n> +\n> +\treturn 0;\n> +}\n> +\n> +int CameraCapabilities::initializeStaticMetadata()\n> +{\n> +\tstaticMetadata_ = std::make_unique<CameraMetadata>(64, 1024);\n> +\tif (!staticMetadata_->isValid()) {\n> +\t\tLOG(HAL, Error) << \"Failed to allocate static metadata\";\n> +\t\tstaticMetadata_.reset();\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tconst ControlInfoMap &controlsInfo = camera_->controls();\n> +\tconst ControlList &properties = camera_->properties();\n> +\n> +\t/* Color correction static metadata. */\n> +\t{\n> +\t\tstd::vector<uint8_t> data;\n> +\t\tdata.reserve(3);\n> +\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::ColorCorrectionAberrationMode);\n> +\t\tif (infoMap != controlsInfo.end()) {\n> +\t\t\tfor (const auto &value : infoMap->second.values())\n> +\t\t\t\tdata.push_back(value.get<int32_t>());\n> +\t\t} else {\n> +\t\t\tdata.push_back(ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF);\n> +\t\t}\n> +\t\tstaticMetadata_->addEntry(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,\n> +\t\t\t\t\t  data);\n> +\t}\n> +\n> +\t/* Control static metadata. */\n> +\tstd::vector<uint8_t> aeAvailableAntiBandingModes = {\n> +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF,\n> +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ,\n> +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ,\n> +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,\n> +\t\t\t\t  aeAvailableAntiBandingModes);\n> +\n> +\tstd::vector<uint8_t> aeAvailableModes = {\n> +\t\tANDROID_CONTROL_AE_MODE_ON,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_MODES,\n> +\t\t\t\t  aeAvailableModes);\n> +\n> +\tint64_t minFrameDurationNsec = -1;\n> +\tint64_t maxFrameDurationNsec = -1;\n> +\tconst auto frameDurationsInfo = controlsInfo.find(&controls::FrameDurationLimits);\n> +\tif (frameDurationsInfo != controlsInfo.end()) {\n> +\t\tminFrameDurationNsec = frameDurationsInfo->second.min().get<int64_t>() * 1000;\n> +\t\tmaxFrameDurationNsec = frameDurationsInfo->second.max().get<int64_t>() * 1000;\n> +\n> +\t\t/*\n> +\t\t * Adjust the minimum frame duration to comply with Android\n> +\t\t * requirements. The camera service mandates all preview/record\n> +\t\t * streams to have a minimum frame duration < 33,366 milliseconds\n> +\t\t * (see MAX_PREVIEW_RECORD_DURATION_NS in the camera service\n> +\t\t * implementation).\n> +\t\t *\n> +\t\t * If we're close enough (+ 500 useconds) to that value, round\n> +\t\t * the minimum frame duration of the camera to an accepted\n> +\t\t * value.\n> +\t\t */\n> +\t\tstatic constexpr int64_t MAX_PREVIEW_RECORD_DURATION_NS = 1e9 / 29.97;\n> +\t\tif (minFrameDurationNsec > MAX_PREVIEW_RECORD_DURATION_NS &&\n> +\t\t    minFrameDurationNsec < MAX_PREVIEW_RECORD_DURATION_NS + 500000)\n> +\t\t\tminFrameDurationNsec = MAX_PREVIEW_RECORD_DURATION_NS - 1000;\n> +\n> +\t\t/*\n> +\t\t * The AE routine frame rate limits are computed using the frame\n> +\t\t * duration limits, as libcamera clips the AE routine to the\n> +\t\t * frame durations.\n> +\t\t */\n> +\t\tint32_t maxFps = std::round(1e9 / minFrameDurationNsec);\n> +\t\tint32_t minFps = std::round(1e9 / maxFrameDurationNsec);\n> +\t\tminFps = std::max(1, minFps);\n> +\n> +\t\t/*\n> +\t\t * Force rounding errors so that we have the proper frame\n> +\t\t * durations for when we reuse these variables later\n> +\t\t */\n> +\t\tminFrameDurationNsec = 1e9 / maxFps;\n> +\t\tmaxFrameDurationNsec = 1e9 / minFps;\n> +\n> +\t\t/*\n> +\t\t * Register to the camera service {min, max} and {max, max}\n> +\t\t * intervals as requested by the metadata documentation.\n> +\t\t */\n> +\t\tint32_t availableAeFpsTarget[] = {\n> +\t\t\tminFps, maxFps, maxFps, maxFps\n> +\t\t};\n> +\t\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> +\t\t\t\t\t  availableAeFpsTarget);\n> +\t}\n> +\n> +\tstd::vector<int32_t> aeCompensationRange = {\n> +\t\t0, 0,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_RANGE,\n> +\t\t\t\t  aeCompensationRange);\n> +\n> +\tconst camera_metadata_rational_t aeCompensationStep[] = {\n> +\t\t{ 0, 1 }\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_STEP,\n> +\t\t\t\t  aeCompensationStep);\n> +\n> +\tstd::vector<uint8_t> availableAfModes = {\n> +\t\tANDROID_CONTROL_AF_MODE_OFF,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AF_AVAILABLE_MODES,\n> +\t\t\t\t  availableAfModes);\n> +\n> +\tstd::vector<uint8_t> availableEffects = {\n> +\t\tANDROID_CONTROL_EFFECT_MODE_OFF,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_EFFECTS,\n> +\t\t\t\t  availableEffects);\n> +\n> +\tstd::vector<uint8_t> availableSceneModes = {\n> +\t\tANDROID_CONTROL_SCENE_MODE_DISABLED,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_SCENE_MODES,\n> +\t\t\t\t  availableSceneModes);\n> +\n> +\tstd::vector<uint8_t> availableStabilizationModes = {\n> +\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,\n> +\t\t\t\t  availableStabilizationModes);\n> +\n> +\t/*\n> +\t * \\todo Inspect the Camera capabilities to report the available\n> +\t * AWB modes. Default to AUTO as CTS tests require it.\n> +\t */\n> +\tstd::vector<uint8_t> availableAwbModes = {\n> +\t\tANDROID_CONTROL_AWB_MODE_AUTO,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AWB_AVAILABLE_MODES,\n> +\t\t\t\t  availableAwbModes);\n> +\n> +\tstd::vector<int32_t> availableMaxRegions = {\n> +\t\t0, 0, 0,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_MAX_REGIONS,\n> +\t\t\t\t  availableMaxRegions);\n> +\n> +\tstd::vector<uint8_t> sceneModesOverride = {\n> +\t\tANDROID_CONTROL_AE_MODE_ON,\n> +\t\tANDROID_CONTROL_AWB_MODE_AUTO,\n> +\t\tANDROID_CONTROL_AF_MODE_OFF,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_SCENE_MODE_OVERRIDES,\n> +\t\t\t\t  sceneModesOverride);\n> +\n> +\tuint8_t aeLockAvailable = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE;\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE,\n> +\t\t\t\t  aeLockAvailable);\n> +\n> +\tuint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> +\t\t\t\t  awbLockAvailable);\n> +\n> +\tchar availableControlModes = ANDROID_CONTROL_MODE_AUTO;\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_MODES,\n> +\t\t\t\t  availableControlModes);\n> +\n> +\t/* JPEG static metadata. */\n> +\n> +\t/*\n> +\t * Create the list of supported thumbnail sizes by inspecting the\n> +\t * available JPEG resolutions collected in streamConfigurations_ and\n> +\t * generate one entry for each aspect ratio.\n> +\t *\n> +\t * The JPEG thumbnailer can freely scale, so pick an arbitrary\n> +\t * (160, 160) size as the bounding rectangle, which is then cropped to\n> +\t * the different supported aspect ratios.\n> +\t */\n> +\tconstexpr Size maxJpegThumbnail(160, 160);\n> +\tstd::vector<Size> thumbnailSizes;\n> +\tthumbnailSizes.push_back({ 0, 0 });\n> +\tfor (const auto &entry : streamConfigurations_) {\n> +\t\tif (entry.androidFormat != HAL_PIXEL_FORMAT_BLOB)\n> +\t\t\tcontinue;\n> +\n> +\t\tSize thumbnailSize = maxJpegThumbnail\n> +\t\t\t\t     .boundedToAspectRatio({ entry.resolution.width,\n> +\t\t\t\t\t\t\t     entry.resolution.height });\n> +\t\tthumbnailSizes.push_back(thumbnailSize);\n> +\t}\n> +\n> +\tstd::sort(thumbnailSizes.begin(), thumbnailSizes.end());\n> +\tauto last = std::unique(thumbnailSizes.begin(), thumbnailSizes.end());\n> +\tthumbnailSizes.erase(last, thumbnailSizes.end());\n> +\n> +\t/* Transform sizes in to a list of integers that can be consumed. */\n> +\tstd::vector<int32_t> thumbnailEntries;\n> +\tthumbnailEntries.reserve(thumbnailSizes.size() * 2);\n> +\tfor (const auto &size : thumbnailSizes) {\n> +\t\tthumbnailEntries.push_back(size.width);\n> +\t\tthumbnailEntries.push_back(size.height);\n> +\t}\n> +\tstaticMetadata_->addEntry(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,\n> +\t\t\t\t  thumbnailEntries);\n> +\n> +\tstaticMetadata_->addEntry(ANDROID_JPEG_MAX_SIZE, maxJpegBufferSize_);\n> +\n> +\t/* Sensor static metadata. */\n> +\tstd::array<int32_t, 2> pixelArraySize;\n> +\t{\n> +\t\tconst Size &size = properties.get(properties::PixelArraySize);\n> +\t\tpixelArraySize[0] = size.width;\n> +\t\tpixelArraySize[1] = size.height;\n> +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,\n> +\t\t\t\t\t  pixelArraySize);\n> +\t}\n> +\n> +\tif (properties.contains(properties::UnitCellSize)) {\n> +\t\tconst Size &cellSize = properties.get<Size>(properties::UnitCellSize);\n> +\t\tstd::array<float, 2> physicalSize{\n> +\t\t\tcellSize.width * pixelArraySize[0] / 1e6f,\n> +\t\t\tcellSize.height * pixelArraySize[1] / 1e6f\n> +\t\t};\n> +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,\n> +\t\t\t\t\t  physicalSize);\n> +\t}\n> +\n> +\t{\n> +\t\tconst Span<const Rectangle> &rects =\n> +\t\t\tproperties.get(properties::PixelArrayActiveAreas);\n> +\t\tstd::vector<int32_t> data{\n> +\t\t\tstatic_cast<int32_t>(rects[0].x),\n> +\t\t\tstatic_cast<int32_t>(rects[0].y),\n> +\t\t\tstatic_cast<int32_t>(rects[0].width),\n> +\t\t\tstatic_cast<int32_t>(rects[0].height),\n> +\t\t};\n> +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,\n> +\t\t\t\t\t  data);\n> +\t}\n> +\n> +\tint32_t sensitivityRange[] = {\n> +\t\t32, 2400,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,\n> +\t\t\t\t  sensitivityRange);\n> +\n> +\t/* Report the color filter arrangement if the camera reports it. */\n> +\tif (properties.contains(properties::draft::ColorFilterArrangement)) {\n> +\t\tuint8_t filterArr = properties.get(properties::draft::ColorFilterArrangement);\n> +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,\n> +\t\t\t\t\t  filterArr);\n> +\t}\n> +\n> +\tconst auto &exposureInfo = controlsInfo.find(&controls::ExposureTime);\n> +\tif (exposureInfo != controlsInfo.end()) {\n> +\t\tint64_t exposureTimeRange[2] = {\n> +\t\t\texposureInfo->second.min().get<int32_t>() * 1000LL,\n> +\t\t\texposureInfo->second.max().get<int32_t>() * 1000LL,\n> +\t\t};\n> +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,\n> +\t\t\t\t\t  exposureTimeRange, 2);\n> +\t}\n> +\n> +\tstaticMetadata_->addEntry(ANDROID_SENSOR_ORIENTATION, orientation_);\n> +\n> +\tstd::vector<int32_t> testPatternModes = {\n> +\t\tANDROID_SENSOR_TEST_PATTERN_MODE_OFF\n> +\t};\n> +\tconst auto &testPatternsInfo =\n> +\t\tcontrolsInfo.find(&controls::draft::TestPatternMode);\n> +\tif (testPatternsInfo != controlsInfo.end()) {\n> +\t\tconst auto &values = testPatternsInfo->second.values();\n> +\t\tASSERT(!values.empty());\n> +\t\tfor (const auto &value : values) {\n> +\t\t\tswitch (value.get<int32_t>()) {\n> +\t\t\tcase controls::draft::TestPatternModeOff:\n> +\t\t\t\t/*\n> +\t\t\t\t * ANDROID_SENSOR_TEST_PATTERN_MODE_OFF is\n> +\t\t\t\t * already in testPatternModes.\n> +\t\t\t\t */\n> +\t\t\t\tbreak;\n> +\n> +\t\t\tcase controls::draft::TestPatternModeSolidColor:\n> +\t\t\t\ttestPatternModes.push_back(\n> +\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR);\n> +\t\t\t\tbreak;\n> +\n> +\t\t\tcase controls::draft::TestPatternModeColorBars:\n> +\t\t\t\ttestPatternModes.push_back(\n> +\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS);\n> +\t\t\t\tbreak;\n> +\n> +\t\t\tcase controls::draft::TestPatternModeColorBarsFadeToGray:\n> +\t\t\t\ttestPatternModes.push_back(\n> +\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY);\n> +\t\t\t\tbreak;\n> +\n> +\t\t\tcase controls::draft::TestPatternModePn9:\n> +\t\t\t\ttestPatternModes.push_back(\n> +\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_PN9);\n> +\t\t\t\tbreak;\n> +\n> +\t\t\tcase controls::draft::TestPatternModeCustom1:\n> +\t\t\t\t/* We don't support this yet. */\n> +\t\t\t\tbreak;\n> +\n> +\t\t\tdefault:\n> +\t\t\t\tLOG(HAL, Error) << \"Unknown test pattern mode: \"\n> +\t\t\t\t\t\t<< value.get<int32_t>();\n> +\t\t\t\tcontinue;\n> +\t\t\t}\n> +\t\t}\n> +\t}\n> +\tstaticMetadata_->addEntry(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,\n> +\t\t\t\t  testPatternModes);\n> +\n> +\tuint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;\n> +\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,\n> +\t\t\t\t  timestampSource);\n> +\n> +\tif (maxFrameDurationNsec > 0)\n> +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,\n> +\t\t\t\t\t  maxFrameDurationNsec);\n> +\n> +\t/* Statistics static metadata. */\n> +\tuint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;\n> +\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,\n> +\t\t\t\t  faceDetectMode);\n> +\n> +\tint32_t maxFaceCount = 0;\n> +\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,\n> +\t\t\t\t  maxFaceCount);\n> +\n> +\t{\n> +\t\tstd::vector<uint8_t> data;\n> +\t\tdata.reserve(2);\n> +\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::LensShadingMapMode);\n> +\t\tif (infoMap != controlsInfo.end()) {\n> +\t\t\tfor (const auto &value : infoMap->second.values())\n> +\t\t\t\tdata.push_back(value.get<int32_t>());\n> +\t\t} else {\n> +\t\t\tdata.push_back(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF);\n> +\t\t}\n> +\t\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,\n> +\t\t\t\t\t  data);\n> +\t}\n> +\n> +\t/* Sync static metadata. */\n> +\tint32_t maxLatency = ANDROID_SYNC_MAX_LATENCY_UNKNOWN;\n> +\tstaticMetadata_->addEntry(ANDROID_SYNC_MAX_LATENCY, maxLatency);\n> +\n> +\t/* Flash static metadata. */\n> +\tchar flashAvailable = ANDROID_FLASH_INFO_AVAILABLE_FALSE;\n> +\tstaticMetadata_->addEntry(ANDROID_FLASH_INFO_AVAILABLE,\n> +\t\t\t\t  flashAvailable);\n> +\n> +\t/* Lens static metadata. */\n> +\tstd::vector<float> lensApertures = {\n> +\t\t2.53 / 100,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_APERTURES,\n> +\t\t\t\t  lensApertures);\n> +\n> +\tuint8_t lensFacing;\n> +\tswitch (facing_) {\n> +\tdefault:\n> +\tcase CAMERA_FACING_FRONT:\n> +\t\tlensFacing = ANDROID_LENS_FACING_FRONT;\n> +\t\tbreak;\n> +\tcase CAMERA_FACING_BACK:\n> +\t\tlensFacing = ANDROID_LENS_FACING_BACK;\n> +\t\tbreak;\n> +\tcase CAMERA_FACING_EXTERNAL:\n> +\t\tlensFacing = ANDROID_LENS_FACING_EXTERNAL;\n> +\t\tbreak;\n> +\t}\n> +\tstaticMetadata_->addEntry(ANDROID_LENS_FACING, lensFacing);\n> +\n> +\tstd::vector<float> lensFocalLengths = {\n> +\t\t1,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,\n> +\t\t\t\t  lensFocalLengths);\n> +\n> +\tstd::vector<uint8_t> opticalStabilizations = {\n> +\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,\n> +\t\t\t\t  opticalStabilizations);\n> +\n> +\tfloat hypeFocalDistance = 0;\n> +\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,\n> +\t\t\t\t  hypeFocalDistance);\n> +\n> +\tfloat minFocusDistance = 0;\n> +\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,\n> +\t\t\t\t  minFocusDistance);\n> +\n> +\t/* Noise reduction modes. */\n> +\t{\n> +\t\tstd::vector<uint8_t> data;\n> +\t\tdata.reserve(5);\n> +\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::NoiseReductionMode);\n> +\t\tif (infoMap != controlsInfo.end()) {\n> +\t\t\tfor (const auto &value : infoMap->second.values())\n> +\t\t\t\tdata.push_back(value.get<int32_t>());\n> +\t\t} else {\n> +\t\t\tdata.push_back(ANDROID_NOISE_REDUCTION_MODE_OFF);\n> +\t\t}\n> +\t\tstaticMetadata_->addEntry(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,\n> +\t\t\t\t\t  data);\n> +\t}\n> +\n> +\t/* Scaler static metadata. */\n> +\n> +\t/*\n> +\t * \\todo The digital zoom factor is a property that depends on the\n> +\t * desired output configuration and the sensor frame size input to the\n> +\t * ISP. This information is not available to the Android HAL, not at\n> +\t * initialization time at least.\n> +\t *\n> +\t * As a workaround rely on pipeline handlers initializing the\n> +\t * ScalerCrop control with the camera default configuration and use the\n> +\t * maximum and minimum crop rectangles to calculate the digital zoom\n> +\t * factor.\n> +\t */\n> +\tfloat maxZoom = 1.0f;\n> +\tconst auto scalerCrop = controlsInfo.find(&controls::ScalerCrop);\n> +\tif (scalerCrop != controlsInfo.end()) {\n> +\t\tRectangle min = scalerCrop->second.min().get<Rectangle>();\n> +\t\tRectangle max = scalerCrop->second.max().get<Rectangle>();\n> +\t\tmaxZoom = std::min(1.0f * max.width / min.width,\n> +\t\t\t\t   1.0f * max.height / min.height);\n> +\t}\n> +\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,\n> +\t\t\t\t  maxZoom);\n> +\n> +\tstd::vector<uint32_t> availableStreamConfigurations;\n> +\tavailableStreamConfigurations.reserve(streamConfigurations_.size() * 4);\n> +\tfor (const auto &entry : streamConfigurations_) {\n> +\t\tavailableStreamConfigurations.push_back(entry.androidFormat);\n> +\t\tavailableStreamConfigurations.push_back(entry.resolution.width);\n> +\t\tavailableStreamConfigurations.push_back(entry.resolution.height);\n> +\t\tavailableStreamConfigurations.push_back(\n> +\t\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);\n> +\t}\n> +\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,\n> +\t\t\t\t  availableStreamConfigurations);\n> +\n> +\tstd::vector<int64_t> availableStallDurations = {\n> +\t\tANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920, 33333333,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,\n> +\t\t\t\t  availableStallDurations);\n> +\n> +\t/* Use the minimum frame duration for all the YUV/RGB formats. */\n> +\tif (minFrameDurationNsec > 0) {\n> +\t\tstd::vector<int64_t> minFrameDurations;\n> +\t\tminFrameDurations.reserve(streamConfigurations_.size() * 4);\n> +\t\tfor (const auto &entry : streamConfigurations_) {\n> +\t\t\tminFrameDurations.push_back(entry.androidFormat);\n> +\t\t\tminFrameDurations.push_back(entry.resolution.width);\n> +\t\t\tminFrameDurations.push_back(entry.resolution.height);\n> +\t\t\tminFrameDurations.push_back(minFrameDurationNsec);\n> +\t\t}\n> +\t\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,\n> +\t\t\t\t\t  minFrameDurations);\n> +\t}\n> +\n> +\tuint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY;\n> +\tstaticMetadata_->addEntry(ANDROID_SCALER_CROPPING_TYPE, croppingType);\n> +\n> +\t/* Info static metadata. */\n> +\tuint8_t supportedHWLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;\n> +\tstaticMetadata_->addEntry(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,\n> +\t\t\t\t  supportedHWLevel);\n> +\n> +\t/* Request static metadata. */\n> +\tint32_t partialResultCount = 1;\n> +\tstaticMetadata_->addEntry(ANDROID_REQUEST_PARTIAL_RESULT_COUNT,\n> +\t\t\t\t  partialResultCount);\n> +\n> +\t{\n> +\t\t/* Default the value to 2 if not reported by the camera. */\n> +\t\tuint8_t maxPipelineDepth = 2;\n> +\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::PipelineDepth);\n> +\t\tif (infoMap != controlsInfo.end())\n> +\t\t\tmaxPipelineDepth = infoMap->second.max().get<int32_t>();\n> +\t\tstaticMetadata_->addEntry(ANDROID_REQUEST_PIPELINE_MAX_DEPTH,\n> +\t\t\t\t\t  maxPipelineDepth);\n> +\t}\n> +\n> +\t/* LIMITED does not support reprocessing. */\n> +\tuint32_t maxNumInputStreams = 0;\n> +\tstaticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,\n> +\t\t\t\t  maxNumInputStreams);\n> +\n> +\tstd::vector<uint8_t> availableCapabilities = {\n> +\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,\n> +\t};\n> +\n> +\t/* Report if camera supports RAW. */\n> +\tbool rawStreamAvailable = false;\n> +\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> +\t\tcamera_->generateConfiguration({ StreamRole::Raw });\n> +\tif (cameraConfig && !cameraConfig->empty()) {\n> +\t\tconst PixelFormatInfo &info =\n> +\t\t\tPixelFormatInfo::info(cameraConfig->at(0).pixelFormat);\n> +\t\t/* Only advertise RAW support if RAW16 is possible. */\n> +\t\tif (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW &&\n> +\t\t    info.bitsPerPixel == 16) {\n> +\t\t\trawStreamAvailable = true;\n> +\t\t\tavailableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);\n> +\t\t}\n> +\t}\n> +\n> +\t/* Number of { RAW, YUV, JPEG } supported output streams */\n> +\tint32_t numOutStreams[] = { rawStreamAvailable, 2, 1 };\n> +\tstaticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,\n> +\t\t\t\t  numOutStreams);\n> +\n> +\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CAPABILITIES,\n> +\t\t\t\t  availableCapabilities);\n> +\n> +\tstd::vector<int32_t> availableCharacteristicsKeys = {\n> +\t\tANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,\n> +\t\tANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,\n> +\t\tANDROID_CONTROL_AE_AVAILABLE_MODES,\n> +\t\tANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> +\t\tANDROID_CONTROL_AE_COMPENSATION_RANGE,\n> +\t\tANDROID_CONTROL_AE_COMPENSATION_STEP,\n> +\t\tANDROID_CONTROL_AE_LOCK_AVAILABLE,\n> +\t\tANDROID_CONTROL_AF_AVAILABLE_MODES,\n> +\t\tANDROID_CONTROL_AVAILABLE_EFFECTS,\n> +\t\tANDROID_CONTROL_AVAILABLE_MODES,\n> +\t\tANDROID_CONTROL_AVAILABLE_SCENE_MODES,\n> +\t\tANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,\n> +\t\tANDROID_CONTROL_AWB_AVAILABLE_MODES,\n> +\t\tANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> +\t\tANDROID_CONTROL_MAX_REGIONS,\n> +\t\tANDROID_CONTROL_SCENE_MODE_OVERRIDES,\n> +\t\tANDROID_FLASH_INFO_AVAILABLE,\n> +\t\tANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,\n> +\t\tANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,\n> +\t\tANDROID_JPEG_MAX_SIZE,\n> +\t\tANDROID_LENS_FACING,\n> +\t\tANDROID_LENS_INFO_AVAILABLE_APERTURES,\n> +\t\tANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,\n> +\t\tANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,\n> +\t\tANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,\n> +\t\tANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,\n> +\t\tANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,\n> +\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES,\n> +\t\tANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,\n> +\t\tANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,\n> +\t\tANDROID_REQUEST_PARTIAL_RESULT_COUNT,\n> +\t\tANDROID_REQUEST_PIPELINE_MAX_DEPTH,\n> +\t\tANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,\n> +\t\tANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,\n> +\t\tANDROID_SCALER_AVAILABLE_STALL_DURATIONS,\n> +\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,\n> +\t\tANDROID_SCALER_CROPPING_TYPE,\n> +\t\tANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,\n> +\t\tANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,\n> +\t\tANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,\n> +\t\tANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,\n> +\t\tANDROID_SENSOR_INFO_MAX_FRAME_DURATION,\n> +\t\tANDROID_SENSOR_INFO_PHYSICAL_SIZE,\n> +\t\tANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,\n> +\t\tANDROID_SENSOR_INFO_SENSITIVITY_RANGE,\n> +\t\tANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,\n> +\t\tANDROID_SENSOR_ORIENTATION,\n> +\t\tANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,\n> +\t\tANDROID_STATISTICS_INFO_MAX_FACE_COUNT,\n> +\t\tANDROID_SYNC_MAX_LATENCY,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,\n> +\t\t\t\t  availableCharacteristicsKeys);\n> +\n> +\tstd::vector<int32_t> availableRequestKeys = {\n> +\t\tANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> +\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> +\t\tANDROID_CONTROL_AE_LOCK,\n> +\t\tANDROID_CONTROL_AE_MODE,\n> +\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> +\t\tANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> +\t\tANDROID_CONTROL_AF_MODE,\n> +\t\tANDROID_CONTROL_AF_TRIGGER,\n> +\t\tANDROID_CONTROL_AWB_LOCK,\n> +\t\tANDROID_CONTROL_AWB_MODE,\n> +\t\tANDROID_CONTROL_CAPTURE_INTENT,\n> +\t\tANDROID_CONTROL_EFFECT_MODE,\n> +\t\tANDROID_CONTROL_MODE,\n> +\t\tANDROID_CONTROL_SCENE_MODE,\n> +\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE,\n> +\t\tANDROID_FLASH_MODE,\n> +\t\tANDROID_JPEG_ORIENTATION,\n> +\t\tANDROID_JPEG_QUALITY,\n> +\t\tANDROID_JPEG_THUMBNAIL_QUALITY,\n> +\t\tANDROID_JPEG_THUMBNAIL_SIZE,\n> +\t\tANDROID_LENS_APERTURE,\n> +\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> +\t\tANDROID_NOISE_REDUCTION_MODE,\n> +\t\tANDROID_SCALER_CROP_REGION,\n> +\t\tANDROID_STATISTICS_FACE_DETECT_MODE\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,\n> +\t\t\t\t  availableRequestKeys);\n> +\n> +\tstd::vector<int32_t> availableResultKeys = {\n> +\t\tANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> +\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> +\t\tANDROID_CONTROL_AE_LOCK,\n> +\t\tANDROID_CONTROL_AE_MODE,\n> +\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> +\t\tANDROID_CONTROL_AE_STATE,\n> +\t\tANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> +\t\tANDROID_CONTROL_AF_MODE,\n> +\t\tANDROID_CONTROL_AF_STATE,\n> +\t\tANDROID_CONTROL_AF_TRIGGER,\n> +\t\tANDROID_CONTROL_AWB_LOCK,\n> +\t\tANDROID_CONTROL_AWB_MODE,\n> +\t\tANDROID_CONTROL_AWB_STATE,\n> +\t\tANDROID_CONTROL_CAPTURE_INTENT,\n> +\t\tANDROID_CONTROL_EFFECT_MODE,\n> +\t\tANDROID_CONTROL_MODE,\n> +\t\tANDROID_CONTROL_SCENE_MODE,\n> +\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE,\n> +\t\tANDROID_FLASH_MODE,\n> +\t\tANDROID_FLASH_STATE,\n> +\t\tANDROID_JPEG_GPS_COORDINATES,\n> +\t\tANDROID_JPEG_GPS_PROCESSING_METHOD,\n> +\t\tANDROID_JPEG_GPS_TIMESTAMP,\n> +\t\tANDROID_JPEG_ORIENTATION,\n> +\t\tANDROID_JPEG_QUALITY,\n> +\t\tANDROID_JPEG_SIZE,\n> +\t\tANDROID_JPEG_THUMBNAIL_QUALITY,\n> +\t\tANDROID_JPEG_THUMBNAIL_SIZE,\n> +\t\tANDROID_LENS_APERTURE,\n> +\t\tANDROID_LENS_FOCAL_LENGTH,\n> +\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> +\t\tANDROID_LENS_STATE,\n> +\t\tANDROID_NOISE_REDUCTION_MODE,\n> +\t\tANDROID_REQUEST_PIPELINE_DEPTH,\n> +\t\tANDROID_SCALER_CROP_REGION,\n> +\t\tANDROID_SENSOR_EXPOSURE_TIME,\n> +\t\tANDROID_SENSOR_FRAME_DURATION,\n> +\t\tANDROID_SENSOR_ROLLING_SHUTTER_SKEW,\n> +\t\tANDROID_SENSOR_TEST_PATTERN_MODE,\n> +\t\tANDROID_SENSOR_TIMESTAMP,\n> +\t\tANDROID_STATISTICS_FACE_DETECT_MODE,\n> +\t\tANDROID_STATISTICS_LENS_SHADING_MAP_MODE,\n> +\t\tANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,\n> +\t\tANDROID_STATISTICS_SCENE_FLICKER,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,\n> +\t\t\t\t  availableResultKeys);\n> +\n> +\tif (!staticMetadata_->isValid()) {\n> +\t\tLOG(HAL, Error) << \"Failed to construct static metadata\";\n> +\t\tstaticMetadata_.reset();\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tif (staticMetadata_->resized()) {\n> +\t\tauto [entryCount, dataCount] = staticMetadata_->usage();\n> +\t\tLOG(HAL, Info)\n> +\t\t\t<< \"Static metadata resized: \" << entryCount\n> +\t\t\t<< \" entries and \" << dataCount << \" bytes used\";\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n> +/* Translate Android format code to libcamera pixel format. */\n> +PixelFormat CameraCapabilities::toPixelFormat(int format) const\n> +{\n> +\tauto it = formatsMap_.find(format);\n> +\tif (it == formatsMap_.end()) {\n> +\t\tLOG(HAL, Error) << \"Requested format \" << utils::hex(format)\n> +\t\t\t\t<< \" not supported\";\n> +\t\treturn PixelFormat();\n> +\t}\n> +\n> +\treturn it->second;\n> +}\n> +\n> +std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplatePreview() const\n> +{\n> +\t/*\n> +\t * \\todo Keep this in sync with the actual number of entries.\n> +\t * Currently: 20 entries, 35 bytes\n> +\t */\n> +\tauto requestTemplate = std::make_unique<CameraMetadata>(21, 36);\n> +\tif (!requestTemplate->isValid()) {\n> +\t\treturn nullptr;\n> +\t}\n> +\n> +\t/* Get the FPS range registered in the static metadata. */\n> +\tcamera_metadata_ro_entry_t entry;\n> +\tbool found = staticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> +\t\t\t\t\t       &entry);\n> +\tif (!found) {\n> +\t\tLOG(HAL, Error) << \"Cannot create capture template without FPS range\";\n> +\t\treturn nullptr;\n> +\t}\n> +\n> +\t/*\n> +\t * Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata\n> +\t * has been assembled as {{min, max} {max, max}}.\n> +\t */\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> +\t\t\t\t  entry.data.i32, 2);\n> +\n> +\tuint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_MODE, aeMode);\n> +\n> +\tint32_t aeExposureCompensation = 0;\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> +\t\t\t\t  aeExposureCompensation);\n> +\n> +\tuint8_t aePrecaptureTrigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> +\t\t\t\t  aePrecaptureTrigger);\n> +\n> +\tuint8_t aeLock = ANDROID_CONTROL_AE_LOCK_OFF;\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_LOCK, aeLock);\n> +\n> +\tuint8_t aeAntibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> +\t\t\t\t  aeAntibandingMode);\n> +\n> +\tuint8_t afMode = ANDROID_CONTROL_AF_MODE_OFF;\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_AF_MODE, afMode);\n> +\n> +\tuint8_t afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_AF_TRIGGER, afTrigger);\n> +\n> +\tuint8_t awbMode = ANDROID_CONTROL_AWB_MODE_AUTO;\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_AWB_MODE, awbMode);\n> +\n> +\tuint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_AWB_LOCK, awbLock);\n> +\n> +\tuint8_t flashMode = ANDROID_FLASH_MODE_OFF;\n> +\trequestTemplate->addEntry(ANDROID_FLASH_MODE, flashMode);\n> +\n> +\tuint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;\n> +\trequestTemplate->addEntry(ANDROID_STATISTICS_FACE_DETECT_MODE,\n> +\t\t\t\t  faceDetectMode);\n> +\n> +\tuint8_t noiseReduction = ANDROID_NOISE_REDUCTION_MODE_OFF;\n> +\trequestTemplate->addEntry(ANDROID_NOISE_REDUCTION_MODE,\n> +\t\t\t\t  noiseReduction);\n> +\n> +\tuint8_t aberrationMode = ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF;\n> +\trequestTemplate->addEntry(ANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> +\t\t\t\t  aberrationMode);\n> +\n> +\tuint8_t controlMode = ANDROID_CONTROL_MODE_AUTO;\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_MODE, controlMode);\n> +\n> +\tfloat lensAperture = 2.53 / 100;\n> +\trequestTemplate->addEntry(ANDROID_LENS_APERTURE, lensAperture);\n> +\n> +\tuint8_t opticalStabilization = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;\n> +\trequestTemplate->addEntry(ANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> +\t\t\t\t  opticalStabilization);\n> +\n> +\tuint8_t captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_CAPTURE_INTENT,\n> +\t\t\t\t  captureIntent);\n> +\n> +\treturn requestTemplate;\n> +}\n> +\n> +std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplateVideo() const\n> +{\n> +\tstd::unique_ptr<CameraMetadata> previewTemplate = requestTemplatePreview();\n> +\tif (!previewTemplate)\n> +\t\treturn nullptr;\n> +\n> +\t/*\n> +\t * The video template requires a fixed FPS range. Everything else\n> +\t * stays the same as the preview template.\n> +\t */\n> +\tcamera_metadata_ro_entry_t entry;\n> +\tstaticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> +\t\t\t\t  &entry);\n> +\n> +\t/*\n> +\t * Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata\n> +\t * has been assembled as {{min, max} {max, max}}.\n> +\t */\n> +\tpreviewTemplate->updateEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> +\t\t\t\t     entry.data.i32 + 2, 2);\n> +\n> +\treturn previewTemplate;\n> +}\n> diff --git a/src/android/camera_capabilities.h b/src/android/camera_capabilities.h\n> new file mode 100644\n> index 000000000000..3a427e768aff\n> --- /dev/null\n> +++ b/src/android/camera_capabilities.h\n> @@ -0,0 +1,64 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2021, Google Inc.\n> + *\n> + * camera_capabilities.h - Camera static properties manager\n> + */\n> +#ifndef __ANDROID_CAMERA_CAPABILITIES_H__\n> +#define __ANDROID_CAMERA_CAPABILITIES_H__\n> +\n> +#include <map>\n> +#include <memory>\n> +#include <vector>\n> +\n> +#include <libcamera/camera.h>\n> +#include <libcamera/class.h>\n> +#include <libcamera/geometry.h>\n> +\n> +#include \"camera_metadata.h\"\n> +\n> +class CameraCapabilities\n> +{\n> +public:\n> +\tCameraCapabilities() = default;\n> +\n> +\tint initialize(std::shared_ptr<libcamera::Camera> camera,\n> +\t\t       int orientation, int facing);\n> +\n> +\tCameraMetadata *staticMetadata() const { return staticMetadata_.get(); }\n> +\tlibcamera::PixelFormat toPixelFormat(int format) const;\n\nYou should include libcamera/format.h for PixelFormat.\n\n> +\tunsigned int maxJpegBufferSize() const { return maxJpegBufferSize_; }\n> +\n> +\tstd::unique_ptr<CameraMetadata> requestTemplatePreview() const;\n> +\tstd::unique_ptr<CameraMetadata> requestTemplateVideo() const;\n> +\n> +private:\n> +\tLIBCAMERA_DISABLE_COPY_AND_MOVE(CameraCapabilities)\n> +\n> +\tstruct Camera3StreamConfiguration {\n> +\t\tlibcamera::Size resolution;\n> +\t\tint androidFormat;\n> +\t};\n> +\n> +\tstd::vector<libcamera::Size>\n> +\tgetYUVResolutions(libcamera::CameraConfiguration *cameraConfig,\n\nThis needs libcamera/camera.h.\n\n> +\t\t\t  const libcamera::PixelFormat &pixelFormat,\n> +\t\t\t  const std::vector<libcamera::Size> &resolutions);\n> +\tstd::vector<libcamera::Size>\n> +\tgetRawResolutions(const libcamera::PixelFormat &pixelFormat);\n> +\tint initializeStreamConfigurations();\n> +\n> +\tint initializeStaticMetadata();\n> +\n> +\tstd::shared_ptr<libcamera::Camera> camera_;\n> +\n> +\tint facing_;\n> +\tint orientation_;\n> +\n> +\tstd::vector<Camera3StreamConfiguration> streamConfigurations_;\n> +\tstd::map<int, libcamera::PixelFormat> formatsMap_;\n> +\tstd::unique_ptr<CameraMetadata> staticMetadata_;\n> +\tunsigned int maxJpegBufferSize_;\n> +};\n> +\n> +#endif /* __ANDROID_CAMERA_CAPABILITIES_H__ */\n> diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp\n> index 8c71fd0675d3..4bd125d7020a 100644\n> --- a/src/android/camera_device.cpp\n> +++ b/src/android/camera_device.cpp\n> @@ -10,11 +10,8 @@\n>  #include \"camera_ops.h\"\n>  #include \"post_processor.h\"\n>  \n> -#include <array>\n> -#include <cmath>\n>  #include <fstream>\n>  #include <sys/mman.h>\n> -#include <tuple>\n>  #include <unistd.h>\n>  #include <vector>\n>  \n> @@ -23,7 +20,6 @@\n>  #include <libcamera/formats.h>\n>  #include <libcamera/property_ids.h>\n>  \n> -#include \"libcamera/internal/formats.h\"\n>  #include \"libcamera/internal/log.h\"\n>  #include \"libcamera/internal/thread.h\"\n>  #include \"libcamera/internal/utils.h\"\n> @@ -36,94 +32,6 @@ LOG_DECLARE_CATEGORY(HAL)\n>  \n>  namespace {\n>  \n> -/*\n> - * \\var camera3Resolutions\n> - * \\brief The list of image resolutions defined as mandatory to be supported by\n> - * the Android Camera3 specification\n> - */\n> -const std::vector<Size> camera3Resolutions = {\n> -\t{ 320, 240 },\n> -\t{ 640, 480 },\n> -\t{ 1280, 720 },\n> -\t{ 1920, 1080 }\n> -};\n> -\n> -/*\n> - * \\struct Camera3Format\n> - * \\brief Data associated with an Android format identifier\n> - * \\var libcameraFormats List of libcamera pixel formats compatible with the\n> - * Android format\n> - * \\var name The human-readable representation of the Android format code\n> - */\n> -struct Camera3Format {\n> -\tstd::vector<PixelFormat> libcameraFormats;\n> -\tbool mandatory;\n> -\tconst char *name;\n> -};\n> -\n> -/*\n> - * \\var camera3FormatsMap\n> - * \\brief Associate Android format code with ancillary data\n> - */\n> -const std::map<int, const Camera3Format> camera3FormatsMap = {\n> -\t{\n> -\t\tHAL_PIXEL_FORMAT_BLOB, {\n> -\t\t\t{ formats::MJPEG },\n> -\t\t\ttrue,\n> -\t\t\t\"BLOB\"\n> -\t\t}\n> -\t}, {\n> -\t\tHAL_PIXEL_FORMAT_YCbCr_420_888, {\n> -\t\t\t{ formats::NV12, formats::NV21 },\n> -\t\t\ttrue,\n> -\t\t\t\"YCbCr_420_888\"\n> -\t\t}\n> -\t}, {\n> -\t\t/*\n> -\t\t * \\todo Translate IMPLEMENTATION_DEFINED inspecting the gralloc\n> -\t\t * usage flag. For now, copy the YCbCr_420 configuration.\n> -\t\t */\n> -\t\tHAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, {\n> -\t\t\t{ formats::NV12, formats::NV21 },\n> -\t\t\ttrue,\n> -\t\t\t\"IMPLEMENTATION_DEFINED\"\n> -\t\t}\n> -\t}, {\n> -\t\tHAL_PIXEL_FORMAT_RAW10, {\n> -\t\t\t{\n> -\t\t\t\tformats::SBGGR10_CSI2P,\n> -\t\t\t\tformats::SGBRG10_CSI2P,\n> -\t\t\t\tformats::SGRBG10_CSI2P,\n> -\t\t\t\tformats::SRGGB10_CSI2P\n> -\t\t\t},\n> -\t\t\tfalse,\n> -\t\t\t\"RAW10\"\n> -\t\t}\n> -\t}, {\n> -\t\tHAL_PIXEL_FORMAT_RAW12, {\n> -\t\t\t{\n> -\t\t\t\tformats::SBGGR12_CSI2P,\n> -\t\t\t\tformats::SGBRG12_CSI2P,\n> -\t\t\t\tformats::SGRBG12_CSI2P,\n> -\t\t\t\tformats::SRGGB12_CSI2P\n> -\t\t\t},\n> -\t\t\tfalse,\n> -\t\t\t\"RAW12\"\n> -\t\t}\n> -\t}, {\n> -\t\tHAL_PIXEL_FORMAT_RAW16, {\n> -\t\t\t{\n> -\t\t\t\tformats::SBGGR16,\n> -\t\t\t\tformats::SGBRG16,\n> -\t\t\t\tformats::SGRBG16,\n> -\t\t\t\tformats::SRGGB16\n> -\t\t\t},\n> -\t\t\tfalse,\n> -\t\t\t\"RAW16\"\n> -\t\t}\n> -\t},\n> -};\n> -\n>  /*\n>   * \\struct Camera3StreamConfig\n>   * \\brief Data to store StreamConfiguration associated with camera3_stream(s)\n> @@ -512,242 +420,7 @@ int CameraDevice::initialize(const CameraConfigData *cameraConfigData)\n>  \t\torientation_ = 0;\n>  \t}\n\nShouldn't the code above be moved too ?\n\n>  \n> -\t/* Acquire the camera and initialize available stream configurations. */\n> -\tint ret = camera_->acquire();\n> -\tif (ret) {\n> -\t\tLOG(HAL, Error) << \"Failed to temporarily acquire the camera\";\n> -\t\treturn ret;\n> -\t}\n> -\n> -\tret = initializeStreamConfigurations();\n> -\tcamera_->release();\n> -\treturn ret;\n> -}\n> -\n> -std::vector<Size> CameraDevice::getYUVResolutions(CameraConfiguration *cameraConfig,\n> -\t\t\t\t\t\t  const PixelFormat &pixelFormat,\n> -\t\t\t\t\t\t  const std::vector<Size> &resolutions)\n> -{\n> -\tstd::vector<Size> supportedResolutions;\n> -\n> -\tStreamConfiguration &cfg = cameraConfig->at(0);\n> -\tfor (const Size &res : resolutions) {\n> -\t\tcfg.pixelFormat = pixelFormat;\n> -\t\tcfg.size = res;\n> -\n> -\t\tCameraConfiguration::Status status = cameraConfig->validate();\n> -\t\tif (status != CameraConfiguration::Valid) {\n> -\t\t\tLOG(HAL, Debug) << cfg.toString() << \" not supported\";\n> -\t\t\tcontinue;\n> -\t\t}\n> -\n> -\t\tLOG(HAL, Debug) << cfg.toString() << \" supported\";\n> -\n> -\t\tsupportedResolutions.push_back(res);\n> -\t}\n> -\n> -\treturn supportedResolutions;\n> -}\n> -\n> -std::vector<Size> CameraDevice::getRawResolutions(const libcamera::PixelFormat &pixelFormat)\n> -{\n> -\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> -\t\tcamera_->generateConfiguration({ StreamRole::Raw });\n> -\tStreamConfiguration &cfg = cameraConfig->at(0);\n> -\tconst StreamFormats &formats = cfg.formats();\n> -\tstd::vector<Size> supportedResolutions = formats.sizes(pixelFormat);\n> -\n> -\treturn supportedResolutions;\n> -}\n> -\n> -/*\n> - * Initialize the format conversion map to translate from Android format\n> - * identifier to libcamera pixel formats and fill in the list of supported\n> - * stream configurations to be reported to the Android camera framework through\n> - * the static stream configuration metadata.\n> - */\n> -int CameraDevice::initializeStreamConfigurations()\n> -{\n> -\t/*\n> -\t * Get the maximum output resolutions\n> -\t * \\todo Get this from the camera properties once defined\n> -\t */\n> -\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> -\t\tcamera_->generateConfiguration({ StillCapture });\n> -\tif (!cameraConfig) {\n> -\t\tLOG(HAL, Error) << \"Failed to get maximum resolution\";\n> -\t\treturn -EINVAL;\n> -\t}\n> -\tStreamConfiguration &cfg = cameraConfig->at(0);\n> -\n> -\t/*\n> -\t * \\todo JPEG - Adjust the maximum available resolution by taking the\n> -\t * JPEG encoder requirements into account (alignment and aspect ratio).\n> -\t */\n> -\tconst Size maxRes = cfg.size;\n> -\tLOG(HAL, Debug) << \"Maximum supported resolution: \" << maxRes.toString();\n> -\n> -\t/*\n> -\t * Build the list of supported image resolutions.\n> -\t *\n> -\t * The resolutions listed in camera3Resolution are mandatory to be\n> -\t * supported, up to the camera maximum resolution.\n> -\t *\n> -\t * Augment the list by adding resolutions calculated from the camera\n> -\t * maximum one.\n> -\t */\n> -\tstd::vector<Size> cameraResolutions;\n> -\tstd::copy_if(camera3Resolutions.begin(), camera3Resolutions.end(),\n> -\t\t     std::back_inserter(cameraResolutions),\n> -\t\t     [&](const Size &res) { return res < maxRes; });\n> -\n> -\t/*\n> -\t * The Camera3 specification suggests adding 1/2 and 1/4 of the maximum\n> -\t * resolution.\n> -\t */\n> -\tfor (unsigned int divider = 2;; divider <<= 1) {\n> -\t\tSize derivedSize{\n> -\t\t\tmaxRes.width / divider,\n> -\t\t\tmaxRes.height / divider,\n> -\t\t};\n> -\n> -\t\tif (derivedSize.width < 320 ||\n> -\t\t    derivedSize.height < 240)\n> -\t\t\tbreak;\n> -\n> -\t\tcameraResolutions.push_back(derivedSize);\n> -\t}\n> -\tcameraResolutions.push_back(maxRes);\n> -\n> -\t/* Remove duplicated entries from the list of supported resolutions. */\n> -\tstd::sort(cameraResolutions.begin(), cameraResolutions.end());\n> -\tauto last = std::unique(cameraResolutions.begin(), cameraResolutions.end());\n> -\tcameraResolutions.erase(last, cameraResolutions.end());\n> -\n> -\t/*\n> -\t * Build the list of supported camera formats.\n> -\t *\n> -\t * To each Android format a list of compatible libcamera formats is\n> -\t * associated. The first libcamera format that tests successful is added\n> -\t * to the format translation map used when configuring the streams.\n> -\t * It is then tested against the list of supported camera resolutions to\n> -\t * build the stream configuration map reported through the camera static\n> -\t * metadata.\n> -\t */\n> -\tSize maxJpegSize;\n> -\tfor (const auto &format : camera3FormatsMap) {\n> -\t\tint androidFormat = format.first;\n> -\t\tconst Camera3Format &camera3Format = format.second;\n> -\t\tconst std::vector<PixelFormat> &libcameraFormats =\n> -\t\t\tcamera3Format.libcameraFormats;\n> -\n> -\t\tLOG(HAL, Debug) << \"Trying to map Android format \"\n> -\t\t\t\t<< camera3Format.name;\n> -\n> -\t\t/*\n> -\t\t * JPEG is always supported, either produced directly by the\n> -\t\t * camera, or encoded in the HAL.\n> -\t\t */\n> -\t\tif (androidFormat == HAL_PIXEL_FORMAT_BLOB) {\n> -\t\t\tformatsMap_[androidFormat] = formats::MJPEG;\n> -\t\t\tLOG(HAL, Debug) << \"Mapped Android format \"\n> -\t\t\t\t\t<< camera3Format.name << \" to \"\n> -\t\t\t\t\t<< formats::MJPEG.toString()\n> -\t\t\t\t\t<< \" (fixed mapping)\";\n> -\t\t\tcontinue;\n> -\t\t}\n> -\n> -\t\t/*\n> -\t\t * Test the libcamera formats that can produce images\n> -\t\t * compatible with the format defined by Android.\n> -\t\t */\n> -\t\tPixelFormat mappedFormat;\n> -\t\tfor (const PixelFormat &pixelFormat : libcameraFormats) {\n> -\n> -\t\t\tLOG(HAL, Debug) << \"Testing \" << pixelFormat.toString();\n> -\n> -\t\t\t/*\n> -\t\t\t * The stream configuration size can be adjusted,\n> -\t\t\t * not the pixel format.\n> -\t\t\t *\n> -\t\t\t * \\todo This could be simplified once all pipeline\n> -\t\t\t * handlers will report the StreamFormats list of\n> -\t\t\t * supported formats.\n> -\t\t\t */\n> -\t\t\tcfg.pixelFormat = pixelFormat;\n> -\n> -\t\t\tCameraConfiguration::Status status = cameraConfig->validate();\n> -\t\t\tif (status != CameraConfiguration::Invalid &&\n> -\t\t\t    cfg.pixelFormat == pixelFormat) {\n> -\t\t\t\tmappedFormat = pixelFormat;\n> -\t\t\t\tbreak;\n> -\t\t\t}\n> -\t\t}\n> -\n> -\t\tif (!mappedFormat.isValid()) {\n> -\t\t\t/* If the format is not mandatory, skip it. */\n> -\t\t\tif (!camera3Format.mandatory)\n> -\t\t\t\tcontinue;\n> -\n> -\t\t\tLOG(HAL, Error)\n> -\t\t\t\t<< \"Failed to map mandatory Android format \"\n> -\t\t\t\t<< camera3Format.name << \" (\"\n> -\t\t\t\t<< utils::hex(androidFormat) << \"): aborting\";\n> -\t\t\treturn -EINVAL;\n> -\t\t}\n> -\n> -\t\t/*\n> -\t\t * Record the mapping and then proceed to generate the\n> -\t\t * stream configurations map, by testing the image resolutions.\n> -\t\t */\n> -\t\tformatsMap_[androidFormat] = mappedFormat;\n> -\t\tLOG(HAL, Debug) << \"Mapped Android format \"\n> -\t\t\t\t<< camera3Format.name << \" to \"\n> -\t\t\t\t<< mappedFormat.toString();\n> -\n> -\t\tstd::vector<Size> resolutions;\n> -\t\tconst PixelFormatInfo &info = PixelFormatInfo::info(mappedFormat);\n> -\t\tif (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW)\n> -\t\t\tresolutions = getRawResolutions(mappedFormat);\n> -\t\telse\n> -\t\t\tresolutions = getYUVResolutions(cameraConfig.get(),\n> -\t\t\t\t\t\t\tmappedFormat,\n> -\t\t\t\t\t\t\tcameraResolutions);\n> -\n> -\t\tfor (const Size &res : resolutions) {\n> -\t\t\tstreamConfigurations_.push_back({ res, androidFormat });\n> -\n> -\t\t\t/*\n> -\t\t\t * If the format is HAL_PIXEL_FORMAT_YCbCr_420_888\n> -\t\t\t * from which JPEG is produced, add an entry for\n> -\t\t\t * the JPEG stream.\n> -\t\t\t *\n> -\t\t\t * \\todo Wire the JPEG encoder to query the supported\n> -\t\t\t * sizes provided a list of formats it can encode.\n> -\t\t\t *\n> -\t\t\t * \\todo Support JPEG streams produced by the Camera\n> -\t\t\t * natively.\n> -\t\t\t */\n> -\t\t\tif (androidFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {\n> -\t\t\t\tstreamConfigurations_.push_back(\n> -\t\t\t\t\t{ res, HAL_PIXEL_FORMAT_BLOB });\n> -\t\t\t\tmaxJpegSize = std::max(maxJpegSize, res);\n> -\t\t\t}\n> -\t\t}\n> -\n> -\t\t/*\n> -\t\t * \\todo Calculate the maximum JPEG buffer size by asking the\n> -\t\t * encoder giving the maximum frame size required.\n> -\t\t */\n> -\t\tmaxJpegBufferSize_ = maxJpegSize.width * maxJpegSize.height * 1.5;\n> -\t}\n> -\n> -\tLOG(HAL, Debug) << \"Collected stream configuration map: \";\n> -\tfor (const auto &entry : streamConfigurations_)\n> -\t\tLOG(HAL, Debug) << \"{ \" << entry.resolution.toString() << \" - \"\n> -\t\t\t\t<< utils::hex(entry.androidFormat) << \" }\";\n> -\n> -\treturn 0;\n> +\treturn capabilities_.initialize(camera_, orientation_, facing_);\n>  }\n>  \n>  /*\n> @@ -817,802 +490,19 @@ void CameraDevice::stop()\n>  \tstate_ = State::Stopped;\n>  }\n>  \n> -void CameraDevice::setCallbacks(const camera3_callback_ops_t *callbacks)\n> +unsigned int CameraDevice::maxJpegBufferSize() const\n>  {\n> -\tcallbacks_ = callbacks;\n> +\treturn capabilities_.maxJpegBufferSize();\n>  }\n>  \n> -/*\n> - * Return static information for the camera.\n> - */\n> -const camera_metadata_t *CameraDevice::getStaticMetadata()\n> -{\n> -\tif (staticMetadata_)\n> -\t\treturn staticMetadata_->get();\n> -\n> -\tstaticMetadata_ = std::make_unique<CameraMetadata>(64, 1024);\n> -\tif (!staticMetadata_->isValid()) {\n> -\t\tLOG(HAL, Error) << \"Failed to allocate static metadata\";\n> -\t\tstaticMetadata_.reset();\n> -\t\treturn nullptr;\n> -\t}\n> -\n> -\tconst ControlInfoMap &controlsInfo = camera_->controls();\n> -\tconst ControlList &properties = camera_->properties();\n> -\n> -\t/* Color correction static metadata. */\n> -\t{\n> -\t\tstd::vector<uint8_t> data;\n> -\t\tdata.reserve(3);\n> -\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::ColorCorrectionAberrationMode);\n> -\t\tif (infoMap != controlsInfo.end()) {\n> -\t\t\tfor (const auto &value : infoMap->second.values())\n> -\t\t\t\tdata.push_back(value.get<int32_t>());\n> -\t\t} else {\n> -\t\t\tdata.push_back(ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF);\n> -\t\t}\n> -\t\tstaticMetadata_->addEntry(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,\n> -\t\t\t\t\t  data);\n> -\t}\n> -\n> -\t/* Control static metadata. */\n> -\tstd::vector<uint8_t> aeAvailableAntiBandingModes = {\n> -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF,\n> -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ,\n> -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ,\n> -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,\n> -\t\t\t\t  aeAvailableAntiBandingModes);\n> -\n> -\tstd::vector<uint8_t> aeAvailableModes = {\n> -\t\tANDROID_CONTROL_AE_MODE_ON,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_MODES,\n> -\t\t\t\t  aeAvailableModes);\n> -\n> -\tint64_t minFrameDurationNsec = -1;\n> -\tint64_t maxFrameDurationNsec = -1;\n> -\tconst auto frameDurationsInfo = controlsInfo.find(&controls::FrameDurationLimits);\n> -\tif (frameDurationsInfo != controlsInfo.end()) {\n> -\t\tminFrameDurationNsec = frameDurationsInfo->second.min().get<int64_t>() * 1000;\n> -\t\tmaxFrameDurationNsec = frameDurationsInfo->second.max().get<int64_t>() * 1000;\n> -\n> -\t\t/*\n> -\t\t * Adjust the minimum frame duration to comply with Android\n> -\t\t * requirements. The camera service mandates all preview/record\n> -\t\t * streams to have a minimum frame duration < 33,366 milliseconds\n> -\t\t * (see MAX_PREVIEW_RECORD_DURATION_NS in the camera service\n> -\t\t * implementation).\n> -\t\t *\n> -\t\t * If we're close enough (+ 500 useconds) to that value, round\n> -\t\t * the minimum frame duration of the camera to an accepted\n> -\t\t * value.\n> -\t\t */\n> -\t\tstatic constexpr int64_t MAX_PREVIEW_RECORD_DURATION_NS = 1e9 / 29.97;\n> -\t\tif (minFrameDurationNsec > MAX_PREVIEW_RECORD_DURATION_NS &&\n> -\t\t    minFrameDurationNsec < MAX_PREVIEW_RECORD_DURATION_NS + 500000)\n> -\t\t\tminFrameDurationNsec = MAX_PREVIEW_RECORD_DURATION_NS - 1000;\n> -\n> -\t\t/*\n> -\t\t * The AE routine frame rate limits are computed using the frame\n> -\t\t * duration limits, as libcamera clips the AE routine to the\n> -\t\t * frame durations.\n> -\t\t */\n> -\t\tint32_t maxFps = std::round(1e9 / minFrameDurationNsec);\n> -\t\tint32_t minFps = std::round(1e9 / maxFrameDurationNsec);\n> -\t\tminFps = std::max(1, minFps);\n> -\n> -\t\t/*\n> -\t\t * Force rounding errors so that we have the proper frame\n> -\t\t * durations for when we reuse these variables later\n> -\t\t */\n> -\t\tminFrameDurationNsec = 1e9 / maxFps;\n> -\t\tmaxFrameDurationNsec = 1e9 / minFps;\n> -\n> -\t\t/*\n> -\t\t * Register to the camera service {min, max} and {max, max}\n> -\t\t * intervals as requested by the metadata documentation.\n> -\t\t */\n> -\t\tint32_t availableAeFpsTarget[] = {\n> -\t\t\tminFps, maxFps, maxFps, maxFps\n> -\t\t};\n> -\t\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> -\t\t\t\t\t  availableAeFpsTarget);\n> -\t}\n> -\n> -\tstd::vector<int32_t> aeCompensationRange = {\n> -\t\t0, 0,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_RANGE,\n> -\t\t\t\t  aeCompensationRange);\n> -\n> -\tconst camera_metadata_rational_t aeCompensationStep[] = {\n> -\t\t{ 0, 1 }\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_STEP,\n> -\t\t\t\t  aeCompensationStep);\n> -\n> -\tstd::vector<uint8_t> availableAfModes = {\n> -\t\tANDROID_CONTROL_AF_MODE_OFF,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AF_AVAILABLE_MODES,\n> -\t\t\t\t  availableAfModes);\n> -\n> -\tstd::vector<uint8_t> availableEffects = {\n> -\t\tANDROID_CONTROL_EFFECT_MODE_OFF,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_EFFECTS,\n> -\t\t\t\t  availableEffects);\n> -\n> -\tstd::vector<uint8_t> availableSceneModes = {\n> -\t\tANDROID_CONTROL_SCENE_MODE_DISABLED,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_SCENE_MODES,\n> -\t\t\t\t  availableSceneModes);\n> -\n> -\tstd::vector<uint8_t> availableStabilizationModes = {\n> -\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,\n> -\t\t\t\t  availableStabilizationModes);\n> -\n> -\t/*\n> -\t * \\todo Inspect the Camera capabilities to report the available\n> -\t * AWB modes. Default to AUTO as CTS tests require it.\n> -\t */\n> -\tstd::vector<uint8_t> availableAwbModes = {\n> -\t\tANDROID_CONTROL_AWB_MODE_AUTO,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AWB_AVAILABLE_MODES,\n> -\t\t\t\t  availableAwbModes);\n> -\n> -\tstd::vector<int32_t> availableMaxRegions = {\n> -\t\t0, 0, 0,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_MAX_REGIONS,\n> -\t\t\t\t  availableMaxRegions);\n> -\n> -\tstd::vector<uint8_t> sceneModesOverride = {\n> -\t\tANDROID_CONTROL_AE_MODE_ON,\n> -\t\tANDROID_CONTROL_AWB_MODE_AUTO,\n> -\t\tANDROID_CONTROL_AF_MODE_OFF,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_SCENE_MODE_OVERRIDES,\n> -\t\t\t\t  sceneModesOverride);\n> -\n> -\tuint8_t aeLockAvailable = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE;\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE,\n> -\t\t\t\t  aeLockAvailable);\n> -\n> -\tuint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> -\t\t\t\t  awbLockAvailable);\n> -\n> -\tchar availableControlModes = ANDROID_CONTROL_MODE_AUTO;\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_MODES,\n> -\t\t\t\t  availableControlModes);\n> -\n> -\t/* JPEG static metadata. */\n> -\n> -\t/*\n> -\t * Create the list of supported thumbnail sizes by inspecting the\n> -\t * available JPEG resolutions collected in streamConfigurations_ and\n> -\t * generate one entry for each aspect ratio.\n> -\t *\n> -\t * The JPEG thumbnailer can freely scale, so pick an arbitrary\n> -\t * (160, 160) size as the bounding rectangle, which is then cropped to\n> -\t * the different supported aspect ratios.\n> -\t */\n> -\tconstexpr Size maxJpegThumbnail(160, 160);\n> -\tstd::vector<Size> thumbnailSizes;\n> -\tthumbnailSizes.push_back({ 0, 0 });\n> -\tfor (const auto &entry : streamConfigurations_) {\n> -\t\tif (entry.androidFormat != HAL_PIXEL_FORMAT_BLOB)\n> -\t\t\tcontinue;\n> -\n> -\t\tSize thumbnailSize = maxJpegThumbnail\n> -\t\t\t\t     .boundedToAspectRatio({ entry.resolution.width,\n> -\t\t\t\t\t\t\t     entry.resolution.height });\n> -\t\tthumbnailSizes.push_back(thumbnailSize);\n> -\t}\n> -\n> -\tstd::sort(thumbnailSizes.begin(), thumbnailSizes.end());\n> -\tauto last = std::unique(thumbnailSizes.begin(), thumbnailSizes.end());\n> -\tthumbnailSizes.erase(last, thumbnailSizes.end());\n> -\n> -\t/* Transform sizes in to a list of integers that can be consumed. */\n> -\tstd::vector<int32_t> thumbnailEntries;\n> -\tthumbnailEntries.reserve(thumbnailSizes.size() * 2);\n> -\tfor (const auto &size : thumbnailSizes) {\n> -\t\tthumbnailEntries.push_back(size.width);\n> -\t\tthumbnailEntries.push_back(size.height);\n> -\t}\n> -\tstaticMetadata_->addEntry(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,\n> -\t\t\t\t  thumbnailEntries);\n> -\n> -\tstaticMetadata_->addEntry(ANDROID_JPEG_MAX_SIZE, maxJpegBufferSize_);\n> -\n> -\t/* Sensor static metadata. */\n> -\tstd::array<int32_t, 2> pixelArraySize;\n> -\t{\n> -\t\tconst Size &size = properties.get(properties::PixelArraySize);\n> -\t\tpixelArraySize[0] = size.width;\n> -\t\tpixelArraySize[1] = size.height;\n> -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,\n> -\t\t\t\t\t  pixelArraySize);\n> -\t}\n> -\n> -\tif (properties.contains(properties::UnitCellSize)) {\n> -\t\tconst Size &cellSize = properties.get<Size>(properties::UnitCellSize);\n> -\t\tstd::array<float, 2> physicalSize{\n> -\t\t\tcellSize.width * pixelArraySize[0] / 1e6f,\n> -\t\t\tcellSize.height * pixelArraySize[1] / 1e6f\n> -\t\t};\n> -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,\n> -\t\t\t\t\t  physicalSize);\n> -\t}\n> -\n> -\t{\n> -\t\tconst Span<const Rectangle> &rects =\n> -\t\t\tproperties.get(properties::PixelArrayActiveAreas);\n> -\t\tstd::vector<int32_t> data{\n> -\t\t\tstatic_cast<int32_t>(rects[0].x),\n> -\t\t\tstatic_cast<int32_t>(rects[0].y),\n> -\t\t\tstatic_cast<int32_t>(rects[0].width),\n> -\t\t\tstatic_cast<int32_t>(rects[0].height),\n> -\t\t};\n> -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,\n> -\t\t\t\t\t  data);\n> -\t}\n> -\n> -\tint32_t sensitivityRange[] = {\n> -\t\t32, 2400,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,\n> -\t\t\t\t  sensitivityRange);\n> -\n> -\t/* Report the color filter arrangement if the camera reports it. */\n> -\tif (properties.contains(properties::draft::ColorFilterArrangement)) {\n> -\t\tuint8_t filterArr = properties.get(properties::draft::ColorFilterArrangement);\n> -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,\n> -\t\t\t\t\t  filterArr);\n> -\t}\n> -\n> -\tconst auto &exposureInfo = controlsInfo.find(&controls::ExposureTime);\n> -\tif (exposureInfo != controlsInfo.end()) {\n> -\t\tint64_t exposureTimeRange[2] = {\n> -\t\t\texposureInfo->second.min().get<int32_t>() * 1000LL,\n> -\t\t\texposureInfo->second.max().get<int32_t>() * 1000LL,\n> -\t\t};\n> -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,\n> -\t\t\t\t\t  exposureTimeRange, 2);\n> -\t}\n> -\n> -\tstaticMetadata_->addEntry(ANDROID_SENSOR_ORIENTATION, orientation_);\n> -\n> -\tstd::vector<int32_t> testPatternModes = {\n> -\t\tANDROID_SENSOR_TEST_PATTERN_MODE_OFF\n> -\t};\n> -\tconst auto &testPatternsInfo =\n> -\t\tcontrolsInfo.find(&controls::draft::TestPatternMode);\n> -\tif (testPatternsInfo != controlsInfo.end()) {\n> -\t\tconst auto &values = testPatternsInfo->second.values();\n> -\t\tASSERT(!values.empty());\n> -\t\tfor (const auto &value : values) {\n> -\t\t\tswitch (value.get<int32_t>()) {\n> -\t\t\tcase controls::draft::TestPatternModeOff:\n> -\t\t\t\t/*\n> -\t\t\t\t * ANDROID_SENSOR_TEST_PATTERN_MODE_OFF is\n> -\t\t\t\t * already in testPatternModes.\n> -\t\t\t\t */\n> -\t\t\t\tbreak;\n> -\n> -\t\t\tcase controls::draft::TestPatternModeSolidColor:\n> -\t\t\t\ttestPatternModes.push_back(\n> -\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR);\n> -\t\t\t\tbreak;\n> -\n> -\t\t\tcase controls::draft::TestPatternModeColorBars:\n> -\t\t\t\ttestPatternModes.push_back(\n> -\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS);\n> -\t\t\t\tbreak;\n> -\n> -\t\t\tcase controls::draft::TestPatternModeColorBarsFadeToGray:\n> -\t\t\t\ttestPatternModes.push_back(\n> -\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY);\n> -\t\t\t\tbreak;\n> -\n> -\t\t\tcase controls::draft::TestPatternModePn9:\n> -\t\t\t\ttestPatternModes.push_back(\n> -\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_PN9);\n> -\t\t\t\tbreak;\n> -\n> -\t\t\tcase controls::draft::TestPatternModeCustom1:\n> -\t\t\t\t/* We don't support this yet. */\n> -\t\t\t\tbreak;\n> -\n> -\t\t\tdefault:\n> -\t\t\t\tLOG(HAL, Error) << \"Unknown test pattern mode: \"\n> -\t\t\t\t\t\t<< value.get<int32_t>();\n> -\t\t\t\tcontinue;\n> -\t\t\t}\n> -\t\t}\n> -\t}\n> -\tstaticMetadata_->addEntry(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,\n> -\t\t\t\t  testPatternModes);\n> -\n> -\tuint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;\n> -\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,\n> -\t\t\t\t  timestampSource);\n> -\n> -\tif (maxFrameDurationNsec > 0)\n> -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,\n> -\t\t\t\t\t  maxFrameDurationNsec);\n> -\n> -\t/* Statistics static metadata. */\n> -\tuint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;\n> -\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,\n> -\t\t\t\t  faceDetectMode);\n> -\n> -\tint32_t maxFaceCount = 0;\n> -\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,\n> -\t\t\t\t  maxFaceCount);\n> -\n> -\t{\n> -\t\tstd::vector<uint8_t> data;\n> -\t\tdata.reserve(2);\n> -\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::LensShadingMapMode);\n> -\t\tif (infoMap != controlsInfo.end()) {\n> -\t\t\tfor (const auto &value : infoMap->second.values())\n> -\t\t\t\tdata.push_back(value.get<int32_t>());\n> -\t\t} else {\n> -\t\t\tdata.push_back(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF);\n> -\t\t}\n> -\t\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,\n> -\t\t\t\t\t  data);\n> -\t}\n> -\n> -\t/* Sync static metadata. */\n> -\tint32_t maxLatency = ANDROID_SYNC_MAX_LATENCY_UNKNOWN;\n> -\tstaticMetadata_->addEntry(ANDROID_SYNC_MAX_LATENCY, maxLatency);\n> -\n> -\t/* Flash static metadata. */\n> -\tchar flashAvailable = ANDROID_FLASH_INFO_AVAILABLE_FALSE;\n> -\tstaticMetadata_->addEntry(ANDROID_FLASH_INFO_AVAILABLE,\n> -\t\t\t\t  flashAvailable);\n> -\n> -\t/* Lens static metadata. */\n> -\tstd::vector<float> lensApertures = {\n> -\t\t2.53 / 100,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_APERTURES,\n> -\t\t\t\t  lensApertures);\n> -\n> -\tuint8_t lensFacing;\n> -\tswitch (facing_) {\n> -\tdefault:\n> -\tcase CAMERA_FACING_FRONT:\n> -\t\tlensFacing = ANDROID_LENS_FACING_FRONT;\n> -\t\tbreak;\n> -\tcase CAMERA_FACING_BACK:\n> -\t\tlensFacing = ANDROID_LENS_FACING_BACK;\n> -\t\tbreak;\n> -\tcase CAMERA_FACING_EXTERNAL:\n> -\t\tlensFacing = ANDROID_LENS_FACING_EXTERNAL;\n> -\t\tbreak;\n> -\t}\n> -\tstaticMetadata_->addEntry(ANDROID_LENS_FACING, lensFacing);\n> -\n> -\tstd::vector<float> lensFocalLengths = {\n> -\t\t1,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,\n> -\t\t\t\t  lensFocalLengths);\n> -\n> -\tstd::vector<uint8_t> opticalStabilizations = {\n> -\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,\n> -\t\t\t\t  opticalStabilizations);\n> -\n> -\tfloat hypeFocalDistance = 0;\n> -\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,\n> -\t\t\t\t  hypeFocalDistance);\n> -\n> -\tfloat minFocusDistance = 0;\n> -\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,\n> -\t\t\t\t  minFocusDistance);\n> -\n> -\t/* Noise reduction modes. */\n> -\t{\n> -\t\tstd::vector<uint8_t> data;\n> -\t\tdata.reserve(5);\n> -\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::NoiseReductionMode);\n> -\t\tif (infoMap != controlsInfo.end()) {\n> -\t\t\tfor (const auto &value : infoMap->second.values())\n> -\t\t\t\tdata.push_back(value.get<int32_t>());\n> -\t\t} else {\n> -\t\t\tdata.push_back(ANDROID_NOISE_REDUCTION_MODE_OFF);\n> -\t\t}\n> -\t\tstaticMetadata_->addEntry(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,\n> -\t\t\t\t\t  data);\n> -\t}\n> -\n> -\t/* Scaler static metadata. */\n> -\n> -\t/*\n> -\t * \\todo The digital zoom factor is a property that depends on the\n> -\t * desired output configuration and the sensor frame size input to the\n> -\t * ISP. This information is not available to the Android HAL, not at\n> -\t * initialization time at least.\n> -\t *\n> -\t * As a workaround rely on pipeline handlers initializing the\n> -\t * ScalerCrop control with the camera default configuration and use the\n> -\t * maximum and minimum crop rectangles to calculate the digital zoom\n> -\t * factor.\n> -\t */\n> -\tfloat maxZoom = 1.0f;\n> -\tconst auto scalerCrop = controlsInfo.find(&controls::ScalerCrop);\n> -\tif (scalerCrop != controlsInfo.end()) {\n> -\t\tRectangle min = scalerCrop->second.min().get<Rectangle>();\n> -\t\tRectangle max = scalerCrop->second.max().get<Rectangle>();\n> -\t\tmaxZoom = std::min(1.0f * max.width / min.width,\n> -\t\t\t\t   1.0f * max.height / min.height);\n> -\t}\n> -\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,\n> -\t\t\t\t  maxZoom);\n> -\n> -\tstd::vector<uint32_t> availableStreamConfigurations;\n> -\tavailableStreamConfigurations.reserve(streamConfigurations_.size() * 4);\n> -\tfor (const auto &entry : streamConfigurations_) {\n> -\t\tavailableStreamConfigurations.push_back(entry.androidFormat);\n> -\t\tavailableStreamConfigurations.push_back(entry.resolution.width);\n> -\t\tavailableStreamConfigurations.push_back(entry.resolution.height);\n> -\t\tavailableStreamConfigurations.push_back(\n> -\t\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);\n> -\t}\n> -\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,\n> -\t\t\t\t  availableStreamConfigurations);\n> -\n> -\tstd::vector<int64_t> availableStallDurations = {\n> -\t\tANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920, 33333333,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,\n> -\t\t\t\t  availableStallDurations);\n> -\n> -\t/* Use the minimum frame duration for all the YUV/RGB formats. */\n> -\tif (minFrameDurationNsec > 0) {\n> -\t\tstd::vector<int64_t> minFrameDurations;\n> -\t\tminFrameDurations.reserve(streamConfigurations_.size() * 4);\n> -\t\tfor (const auto &entry : streamConfigurations_) {\n> -\t\t\tminFrameDurations.push_back(entry.androidFormat);\n> -\t\t\tminFrameDurations.push_back(entry.resolution.width);\n> -\t\t\tminFrameDurations.push_back(entry.resolution.height);\n> -\t\t\tminFrameDurations.push_back(minFrameDurationNsec);\n> -\t\t}\n> -\t\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,\n> -\t\t\t\t\t  minFrameDurations);\n> -\t}\n> -\n> -\tuint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY;\n> -\tstaticMetadata_->addEntry(ANDROID_SCALER_CROPPING_TYPE, croppingType);\n> -\n> -\t/* Info static metadata. */\n> -\tuint8_t supportedHWLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;\n> -\tstaticMetadata_->addEntry(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,\n> -\t\t\t\t  supportedHWLevel);\n> -\n> -\t/* Request static metadata. */\n> -\tint32_t partialResultCount = 1;\n> -\tstaticMetadata_->addEntry(ANDROID_REQUEST_PARTIAL_RESULT_COUNT,\n> -\t\t\t\t  partialResultCount);\n> -\n> -\t{\n> -\t\t/* Default the value to 2 if not reported by the camera. */\n> -\t\tuint8_t maxPipelineDepth = 2;\n> -\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::PipelineDepth);\n> -\t\tif (infoMap != controlsInfo.end())\n> -\t\t\tmaxPipelineDepth = infoMap->second.max().get<int32_t>();\n> -\t\tstaticMetadata_->addEntry(ANDROID_REQUEST_PIPELINE_MAX_DEPTH,\n> -\t\t\t\t\t  maxPipelineDepth);\n> -\t}\n> -\n> -\t/* LIMITED does not support reprocessing. */\n> -\tuint32_t maxNumInputStreams = 0;\n> -\tstaticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,\n> -\t\t\t\t  maxNumInputStreams);\n> -\n> -\tstd::vector<uint8_t> availableCapabilities = {\n> -\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,\n> -\t};\n> -\n> -\t/* Report if camera supports RAW. */\n> -\tbool rawStreamAvailable = false;\n> -\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> -\t\tcamera_->generateConfiguration({ StreamRole::Raw });\n> -\tif (cameraConfig && !cameraConfig->empty()) {\n> -\t\tconst PixelFormatInfo &info =\n> -\t\t\tPixelFormatInfo::info(cameraConfig->at(0).pixelFormat);\n> -\t\t/* Only advertise RAW support if RAW16 is possible. */\n> -\t\tif (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW &&\n> -\t\t    info.bitsPerPixel == 16) {\n> -\t\t\trawStreamAvailable = true;\n> -\t\t\tavailableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);\n> -\t\t}\n> -\t}\n> -\n> -\t/* Number of { RAW, YUV, JPEG } supported output streams */\n> -\tint32_t numOutStreams[] = { rawStreamAvailable, 2, 1 };\n> -\tstaticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,\n> -\t\t\t\t  numOutStreams);\n> -\n> -\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CAPABILITIES,\n> -\t\t\t\t  availableCapabilities);\n> -\n> -\tstd::vector<int32_t> availableCharacteristicsKeys = {\n> -\t\tANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,\n> -\t\tANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,\n> -\t\tANDROID_CONTROL_AE_AVAILABLE_MODES,\n> -\t\tANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> -\t\tANDROID_CONTROL_AE_COMPENSATION_RANGE,\n> -\t\tANDROID_CONTROL_AE_COMPENSATION_STEP,\n> -\t\tANDROID_CONTROL_AE_LOCK_AVAILABLE,\n> -\t\tANDROID_CONTROL_AF_AVAILABLE_MODES,\n> -\t\tANDROID_CONTROL_AVAILABLE_EFFECTS,\n> -\t\tANDROID_CONTROL_AVAILABLE_MODES,\n> -\t\tANDROID_CONTROL_AVAILABLE_SCENE_MODES,\n> -\t\tANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,\n> -\t\tANDROID_CONTROL_AWB_AVAILABLE_MODES,\n> -\t\tANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> -\t\tANDROID_CONTROL_MAX_REGIONS,\n> -\t\tANDROID_CONTROL_SCENE_MODE_OVERRIDES,\n> -\t\tANDROID_FLASH_INFO_AVAILABLE,\n> -\t\tANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,\n> -\t\tANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,\n> -\t\tANDROID_JPEG_MAX_SIZE,\n> -\t\tANDROID_LENS_FACING,\n> -\t\tANDROID_LENS_INFO_AVAILABLE_APERTURES,\n> -\t\tANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,\n> -\t\tANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,\n> -\t\tANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,\n> -\t\tANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,\n> -\t\tANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,\n> -\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES,\n> -\t\tANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,\n> -\t\tANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,\n> -\t\tANDROID_REQUEST_PARTIAL_RESULT_COUNT,\n> -\t\tANDROID_REQUEST_PIPELINE_MAX_DEPTH,\n> -\t\tANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,\n> -\t\tANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,\n> -\t\tANDROID_SCALER_AVAILABLE_STALL_DURATIONS,\n> -\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,\n> -\t\tANDROID_SCALER_CROPPING_TYPE,\n> -\t\tANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,\n> -\t\tANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,\n> -\t\tANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,\n> -\t\tANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,\n> -\t\tANDROID_SENSOR_INFO_MAX_FRAME_DURATION,\n> -\t\tANDROID_SENSOR_INFO_PHYSICAL_SIZE,\n> -\t\tANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,\n> -\t\tANDROID_SENSOR_INFO_SENSITIVITY_RANGE,\n> -\t\tANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,\n> -\t\tANDROID_SENSOR_ORIENTATION,\n> -\t\tANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,\n> -\t\tANDROID_STATISTICS_INFO_MAX_FACE_COUNT,\n> -\t\tANDROID_SYNC_MAX_LATENCY,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,\n> -\t\t\t\t  availableCharacteristicsKeys);\n> -\n> -\tstd::vector<int32_t> availableRequestKeys = {\n> -\t\tANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> -\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> -\t\tANDROID_CONTROL_AE_LOCK,\n> -\t\tANDROID_CONTROL_AE_MODE,\n> -\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> -\t\tANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> -\t\tANDROID_CONTROL_AF_MODE,\n> -\t\tANDROID_CONTROL_AF_TRIGGER,\n> -\t\tANDROID_CONTROL_AWB_LOCK,\n> -\t\tANDROID_CONTROL_AWB_MODE,\n> -\t\tANDROID_CONTROL_CAPTURE_INTENT,\n> -\t\tANDROID_CONTROL_EFFECT_MODE,\n> -\t\tANDROID_CONTROL_MODE,\n> -\t\tANDROID_CONTROL_SCENE_MODE,\n> -\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE,\n> -\t\tANDROID_FLASH_MODE,\n> -\t\tANDROID_JPEG_ORIENTATION,\n> -\t\tANDROID_JPEG_QUALITY,\n> -\t\tANDROID_JPEG_THUMBNAIL_QUALITY,\n> -\t\tANDROID_JPEG_THUMBNAIL_SIZE,\n> -\t\tANDROID_LENS_APERTURE,\n> -\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> -\t\tANDROID_NOISE_REDUCTION_MODE,\n> -\t\tANDROID_SCALER_CROP_REGION,\n> -\t\tANDROID_STATISTICS_FACE_DETECT_MODE\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,\n> -\t\t\t\t  availableRequestKeys);\n> -\n> -\tstd::vector<int32_t> availableResultKeys = {\n> -\t\tANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> -\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> -\t\tANDROID_CONTROL_AE_LOCK,\n> -\t\tANDROID_CONTROL_AE_MODE,\n> -\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> -\t\tANDROID_CONTROL_AE_STATE,\n> -\t\tANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> -\t\tANDROID_CONTROL_AF_MODE,\n> -\t\tANDROID_CONTROL_AF_STATE,\n> -\t\tANDROID_CONTROL_AF_TRIGGER,\n> -\t\tANDROID_CONTROL_AWB_LOCK,\n> -\t\tANDROID_CONTROL_AWB_MODE,\n> -\t\tANDROID_CONTROL_AWB_STATE,\n> -\t\tANDROID_CONTROL_CAPTURE_INTENT,\n> -\t\tANDROID_CONTROL_EFFECT_MODE,\n> -\t\tANDROID_CONTROL_MODE,\n> -\t\tANDROID_CONTROL_SCENE_MODE,\n> -\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE,\n> -\t\tANDROID_FLASH_MODE,\n> -\t\tANDROID_FLASH_STATE,\n> -\t\tANDROID_JPEG_GPS_COORDINATES,\n> -\t\tANDROID_JPEG_GPS_PROCESSING_METHOD,\n> -\t\tANDROID_JPEG_GPS_TIMESTAMP,\n> -\t\tANDROID_JPEG_ORIENTATION,\n> -\t\tANDROID_JPEG_QUALITY,\n> -\t\tANDROID_JPEG_SIZE,\n> -\t\tANDROID_JPEG_THUMBNAIL_QUALITY,\n> -\t\tANDROID_JPEG_THUMBNAIL_SIZE,\n> -\t\tANDROID_LENS_APERTURE,\n> -\t\tANDROID_LENS_FOCAL_LENGTH,\n> -\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> -\t\tANDROID_LENS_STATE,\n> -\t\tANDROID_NOISE_REDUCTION_MODE,\n> -\t\tANDROID_REQUEST_PIPELINE_DEPTH,\n> -\t\tANDROID_SCALER_CROP_REGION,\n> -\t\tANDROID_SENSOR_EXPOSURE_TIME,\n> -\t\tANDROID_SENSOR_FRAME_DURATION,\n> -\t\tANDROID_SENSOR_ROLLING_SHUTTER_SKEW,\n> -\t\tANDROID_SENSOR_TEST_PATTERN_MODE,\n> -\t\tANDROID_SENSOR_TIMESTAMP,\n> -\t\tANDROID_STATISTICS_FACE_DETECT_MODE,\n> -\t\tANDROID_STATISTICS_LENS_SHADING_MAP_MODE,\n> -\t\tANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,\n> -\t\tANDROID_STATISTICS_SCENE_FLICKER,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,\n> -\t\t\t\t  availableResultKeys);\n> -\n> -\tif (!staticMetadata_->isValid()) {\n> -\t\tLOG(HAL, Error) << \"Failed to construct static metadata\";\n> -\t\tstaticMetadata_.reset();\n> -\t\treturn nullptr;\n> -\t}\n> -\n> -\tif (staticMetadata_->resized()) {\n> -\t\tauto [entryCount, dataCount] = staticMetadata_->usage();\n> -\t\tLOG(HAL, Info)\n> -\t\t\t<< \"Static metadata resized: \" << entryCount\n> -\t\t\t<< \" entries and \" << dataCount << \" bytes used\";\n> -\t}\n> -\n> -\treturn staticMetadata_->get();\n> -}\n> -\n> -std::unique_ptr<CameraMetadata> CameraDevice::requestTemplatePreview()\n> +void CameraDevice::setCallbacks(const camera3_callback_ops_t *callbacks)\n>  {\n> -\t/*\n> -\t * \\todo Keep this in sync with the actual number of entries.\n> -\t * Currently: 20 entries, 35 bytes\n> -\t */\n> -\tauto requestTemplate = std::make_unique<CameraMetadata>(21, 36);\n> -\tif (!requestTemplate->isValid()) {\n> -\t\treturn nullptr;\n> -\t}\n> -\n> -\t/* Get the FPS range registered in the static metadata. */\n> -\tcamera_metadata_ro_entry_t entry;\n> -\tbool found = staticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> -\t\t\t\t\t       &entry);\n> -\tif (!found) {\n> -\t\tLOG(HAL, Error) << \"Cannot create capture template without FPS range\";\n> -\t\treturn nullptr;\n> -\t}\n> -\n> -\t/*\n> -\t * Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata\n> -\t * has been assembled as {{min, max} {max, max}}.\n> -\t */\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> -\t\t\t\t  entry.data.i32, 2);\n> -\n> -\tuint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_MODE, aeMode);\n> -\n> -\tint32_t aeExposureCompensation = 0;\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> -\t\t\t\t  aeExposureCompensation);\n> -\n> -\tuint8_t aePrecaptureTrigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> -\t\t\t\t  aePrecaptureTrigger);\n> -\n> -\tuint8_t aeLock = ANDROID_CONTROL_AE_LOCK_OFF;\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_LOCK, aeLock);\n> -\n> -\tuint8_t aeAntibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> -\t\t\t\t  aeAntibandingMode);\n> -\n> -\tuint8_t afMode = ANDROID_CONTROL_AF_MODE_OFF;\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_AF_MODE, afMode);\n> -\n> -\tuint8_t afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_AF_TRIGGER, afTrigger);\n> -\n> -\tuint8_t awbMode = ANDROID_CONTROL_AWB_MODE_AUTO;\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_AWB_MODE, awbMode);\n> -\n> -\tuint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_AWB_LOCK, awbLock);\n> -\n> -\tuint8_t flashMode = ANDROID_FLASH_MODE_OFF;\n> -\trequestTemplate->addEntry(ANDROID_FLASH_MODE, flashMode);\n> -\n> -\tuint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;\n> -\trequestTemplate->addEntry(ANDROID_STATISTICS_FACE_DETECT_MODE,\n> -\t\t\t\t  faceDetectMode);\n> -\n> -\tuint8_t noiseReduction = ANDROID_NOISE_REDUCTION_MODE_OFF;\n> -\trequestTemplate->addEntry(ANDROID_NOISE_REDUCTION_MODE,\n> -\t\t\t\t  noiseReduction);\n> -\n> -\tuint8_t aberrationMode = ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF;\n> -\trequestTemplate->addEntry(ANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> -\t\t\t\t  aberrationMode);\n> -\n> -\tuint8_t controlMode = ANDROID_CONTROL_MODE_AUTO;\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_MODE, controlMode);\n> -\n> -\tfloat lensAperture = 2.53 / 100;\n> -\trequestTemplate->addEntry(ANDROID_LENS_APERTURE, lensAperture);\n> -\n> -\tuint8_t opticalStabilization = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;\n> -\trequestTemplate->addEntry(ANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> -\t\t\t\t  opticalStabilization);\n> -\n> -\tuint8_t captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_CAPTURE_INTENT,\n> -\t\t\t\t  captureIntent);\n> -\n> -\treturn requestTemplate;\n> +\tcallbacks_ = callbacks;\n>  }\n>  \n> -std::unique_ptr<CameraMetadata> CameraDevice::requestTemplateVideo()\n> +const camera_metadata_t *CameraDevice::getStaticMetadata()\n>  {\n> -\tstd::unique_ptr<CameraMetadata> previewTemplate = requestTemplatePreview();\n> -\tif (!previewTemplate)\n> -\t\treturn nullptr;\n> -\n> -\t/*\n> -\t * The video template requires a fixed FPS range. Everything else\n> -\t * stays the same as the preview template.\n> -\t */\n> -\tcamera_metadata_ro_entry_t entry;\n> -\tstaticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> -\t\t\t\t  &entry);\n> -\n> -\t/*\n> -\t * Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata\n> -\t * has been assembled as {{min, max} {max, max}}.\n> -\t */\n> -\tpreviewTemplate->updateEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> -\t\t\t\t     entry.data.i32 + 2, 2);\n> -\n> -\treturn previewTemplate;\n> +\treturn capabilities_.staticMetadata()->get();\n>  }\n>  \n>  /*\n> @@ -1630,7 +520,7 @@ const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type)\n>  \tswitch (type) {\n>  \tcase CAMERA3_TEMPLATE_PREVIEW:\n>  \t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;\n> -\t\trequestTemplate = requestTemplatePreview();\n> +\t\trequestTemplate = capabilities_.requestTemplatePreview();\n>  \t\tbreak;\n>  \tcase CAMERA3_TEMPLATE_STILL_CAPTURE:\n>  \t\t/*\n> @@ -1638,15 +528,15 @@ const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type)\n>  \t\t * for the torch mode we currently do not support.\n>  \t\t */\n>  \t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;\n> -\t\trequestTemplate = requestTemplatePreview();\n> +\t\trequestTemplate = capabilities_.requestTemplatePreview();\n>  \t\tbreak;\n>  \tcase CAMERA3_TEMPLATE_VIDEO_RECORD:\n>  \t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;\n> -\t\trequestTemplate = requestTemplateVideo();\n> +\t\trequestTemplate = capabilities_.requestTemplateVideo();\n>  \t\tbreak;\n>  \tcase CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:\n>  \t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;\n> -\t\trequestTemplate = requestTemplateVideo();\n> +\t\trequestTemplate = capabilities_.requestTemplateVideo();\n>  \t\tbreak;\n>  \t/* \\todo Implement templates generation for the remaining use cases. */\n>  \tcase CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:\n> @@ -1668,19 +558,6 @@ const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type)\n>  \treturn requestTemplates_[type]->get();\n>  }\n>  \n> -PixelFormat CameraDevice::toPixelFormat(int format) const\n> -{\n> -\t/* Translate Android format code to libcamera pixel format. */\n> -\tauto it = formatsMap_.find(format);\n> -\tif (it == formatsMap_.end()) {\n> -\t\tLOG(HAL, Error) << \"Requested format \" << utils::hex(format)\n> -\t\t\t\t<< \" not supported\";\n> -\t\treturn PixelFormat();\n> -\t}\n> -\n> -\treturn it->second;\n> -}\n> -\n>  /*\n>   * Inspect the stream_list to produce a list of StreamConfiguration to\n>   * be use to configure the Camera.\n> @@ -1727,7 +604,7 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)\n>  \t\tcamera3_stream_t *stream = stream_list->streams[i];\n>  \t\tSize size(stream->width, stream->height);\n>  \n> -\t\tPixelFormat format = toPixelFormat(stream->format);\n> +\t\tPixelFormat format = capabilities_.toPixelFormat(stream->format);\n>  \n>  \t\tLOG(HAL, Info) << \"Stream #\" << i\n>  \t\t\t       << \", direction: \" << stream->stream_type\n> diff --git a/src/android/camera_device.h b/src/android/camera_device.h\n> index 4aadb27c562c..090fe28a551e 100644\n> --- a/src/android/camera_device.h\n> +++ b/src/android/camera_device.h\n> @@ -10,14 +10,12 @@\n>  #include <map>\n>  #include <memory>\n>  #include <mutex>\n> -#include <tuple>\n>  #include <vector>\n>  \n>  #include <hardware/camera3.h>\n>  \n>  #include <libcamera/buffer.h>\n>  #include <libcamera/camera.h>\n> -#include <libcamera/geometry.h>\n>  #include <libcamera/request.h>\n>  #include <libcamera/stream.h>\n>  \n> @@ -26,6 +24,7 @@\n>  #include \"libcamera/internal/message.h\"\n>  #include \"libcamera/internal/thread.h\"\n>  \n> +#include \"camera_capabilities.h\"\n>  #include \"camera_metadata.h\"\n>  #include \"camera_stream.h\"\n>  #include \"camera_worker.h\"\n> @@ -57,7 +56,7 @@ public:\n>  \tconst std::string &model() const { return model_; }\n>  \tint facing() const { return facing_; }\n>  \tint orientation() const { return orientation_; }\n> -\tunsigned int maxJpegBufferSize() const { return maxJpegBufferSize_; }\n> +\tunsigned int maxJpegBufferSize() const;\n>  \n>  \tvoid setCallbacks(const camera3_callback_ops_t *callbacks);\n>  \tconst camera_metadata_t *getStaticMetadata();\n> @@ -86,11 +85,6 @@ private:\n>  \t\tstd::unique_ptr<CaptureRequest> request_;\n>  \t};\n>  \n> -\tstruct Camera3StreamConfiguration {\n> -\t\tlibcamera::Size resolution;\n> -\t\tint androidFormat;\n> -\t};\n> -\n>  \tenum class State {\n>  \t\tStopped,\n>  \t\tFlushing,\n> @@ -99,22 +93,11 @@ private:\n>  \n>  \tvoid stop();\n>  \n> -\tint initializeStreamConfigurations();\n> -\tstd::vector<libcamera::Size>\n> -\tgetYUVResolutions(libcamera::CameraConfiguration *cameraConfig,\n> -\t\t\t  const libcamera::PixelFormat &pixelFormat,\n> -\t\t\t  const std::vector<libcamera::Size> &resolutions);\n> -\tstd::vector<libcamera::Size>\n> -\tgetRawResolutions(const libcamera::PixelFormat &pixelFormat);\n> -\n>  \tlibcamera::FrameBuffer *createFrameBuffer(const buffer_handle_t camera3buffer);\n>  \tvoid abortRequest(camera3_capture_request_t *request);\n>  \tvoid notifyShutter(uint32_t frameNumber, uint64_t timestamp);\n>  \tvoid notifyError(uint32_t frameNumber, camera3_stream_t *stream,\n>  \t\t\t camera3_error_msg_code code);\n> -\tstd::unique_ptr<CameraMetadata> requestTemplatePreview();\n> -\tstd::unique_ptr<CameraMetadata> requestTemplateVideo();\n> -\tlibcamera::PixelFormat toPixelFormat(int format) const;\n>  \tint processControls(Camera3RequestDescriptor *descriptor);\n>  \tstd::unique_ptr<CameraMetadata> getResultMetadata(\n>  \t\tconst Camera3RequestDescriptor &descriptor) const;\n> @@ -129,13 +112,11 @@ private:\n>  \n>  \tstd::shared_ptr<libcamera::Camera> camera_;\n>  \tstd::unique_ptr<libcamera::CameraConfiguration> config_;\n> +\tCameraCapabilities capabilities_;\n>  \n> -\tstd::unique_ptr<CameraMetadata> staticMetadata_;\n>  \tstd::map<unsigned int, std::unique_ptr<CameraMetadata>> requestTemplates_;\n>  \tconst camera3_callback_ops_t *callbacks_;\n>  \n> -\tstd::vector<Camera3StreamConfiguration> streamConfigurations_;\n> -\tstd::map<int, libcamera::PixelFormat> formatsMap_;\n>  \tstd::vector<CameraStream> streams_;\n>  \n>  \tlibcamera::Mutex descriptorsMutex_; /* Protects descriptors_. */\n> @@ -147,8 +128,6 @@ private:\n>  \tint facing_;\n>  \tint orientation_;\n>  \n> -\tunsigned int maxJpegBufferSize_;\n> -\n>  \tCameraMetadata lastSettings_;\n>  };\n>  \n> diff --git a/src/android/meson.build b/src/android/meson.build\n> index 3893e5b5b832..e093aa2ec565 100644\n> --- a/src/android/meson.build\n> +++ b/src/android/meson.build\n> @@ -45,6 +45,7 @@ subdir('cros')\n>  android_hal_sources = files([\n>      'camera3_hal.cpp',\n>      'camera_hal_manager.cpp',\n> +    'camera_capabilities.cpp',\n\nWhile at it, could you sort this alphabetically ?\n\n>      'camera_device.cpp',\n>      'camera_hal_config.cpp',\n>      'camera_metadata.cpp',","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id DCEC1C3218\n\tfor <parsemail@patchwork.libcamera.org>;\n\tSun, 20 Jun 2021 01:12:38 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 23F8368945;\n\tSun, 20 Jun 2021 03:12:38 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 9F96D60298\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tSun, 20 Jun 2021 03:12:35 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id DD9A4268;\n\tSun, 20 Jun 2021 03:12:34 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"NFcbOLqJ\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1624151555;\n\tbh=4Z9tluS5ixl54k3kRj1g4dQEu4pWisbHL8hyjX2J8So=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=NFcbOLqJewFHxHYx+balsXJYzVjWkV8Guh6pd+XfMwfy751n41SP2CgjJt5budWtj\n\tld+U02vM6+1DsGZ54utbVSLXb/OL9dnj6+a0TS4c/gvANz8LAOHf4goKFnIu9ZJOfS\n\tzqBjrzT/19Ei/t43TI/lSDl79sOarh/M870dDpRM=","Date":"Sun, 20 Jun 2021 04:12:11 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Message-ID":"<YM6V63Kmy3/2zU/Y@pendragon.ideasonboard.com>","References":"<20210619105151.20012-1-jacopo@jmondi.org>\n\t<20210619105151.20012-2-jacopo@jmondi.org>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20210619105151.20012-2-jacopo@jmondi.org>","Subject":"Re: [libcamera-devel] [RFC 1/1] android: Introduce\n\tCameraCapabilties class","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":17654,"web_url":"https://patchwork.libcamera.org/comment/17654/","msgid":"<20210621105445.GA1899306@pyrite.rasen.tech>","date":"2021-06-21T10:54:45","subject":"Re: [libcamera-devel] [RFC 1/1] android: Introduce\n\tCameraCapabilties class","submitter":{"id":17,"url":"https://patchwork.libcamera.org/api/people/17/","name":"Paul Elder","email":"paul.elder@ideasonboard.com"},"content":"Hi Jacopo,\n\nThank you for the patch.\n\nOn Sat, Jun 19, 2021 at 12:51:51PM +0200, Jacopo Mondi wrote:\n> The camera_device.cpp has grown a little too much, and it has quickly\n> become hard to maintain. Break out the handling of the static\n> information collected at camera initialization time to a new\n> CameraCapabilities class.\n> \n> Break out from the camera_device.cpp file all the functions relative to:\n> - Initialization of supported stream configurations\n> - Initialization of static metadata\n> - Initialization of request templates\n> \n> Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n\nI like how the CameraDevice uses the CameraCapabilities, it makes\nCameraDevice a lot cleaner. I was expecting a bit more to reduce\nduplication in the functions that CameraCapabilities has, but that can\nbe done on top. I think this is a good start, and we can build on top of\nthis.\n\nI'm not going to confirm the copy-and-paste :D\n\nAcked-by: Paul Elder <paul.elder@ideasonboard.com>\n\nIt also doesn't regress CTS.\n\nTested-by: Paul Elder <paul.elder@ideasonboard.com>\n\n> ---\n>  src/android/camera_capabilities.cpp | 1165 +++++++++++++++++++++++++++\n>  src/android/camera_capabilities.h   |   64 ++\n>  src/android/camera_device.cpp       | 1147 +-------------------------\n>  src/android/camera_device.h         |   27 +-\n>  src/android/meson.build             |    1 +\n>  5 files changed, 1245 insertions(+), 1159 deletions(-)\n>  create mode 100644 src/android/camera_capabilities.cpp\n>  create mode 100644 src/android/camera_capabilities.h\n> \n> diff --git a/src/android/camera_capabilities.cpp b/src/android/camera_capabilities.cpp\n> new file mode 100644\n> index 000000000000..20df9a6f1abb\n> --- /dev/null\n> +++ b/src/android/camera_capabilities.cpp\n> @@ -0,0 +1,1165 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2021, Google Inc.\n> + *\n> + * camera_capabilities.cpp - Camera static properties manager\n> + */\n> +\n> +#include \"camera_capabilities.h\"\n> +\n> +#include <array>\n> +#include <cmath>\n> +\n> +#include <hardware/camera3.h>\n> +\n> +#include <libcamera/control_ids.h>\n> +#include <libcamera/controls.h>\n> +#include <libcamera/formats.h>\n> +#include <libcamera/property_ids.h>\n> +\n> +#include \"libcamera/internal/formats.h\"\n> +#include \"libcamera/internal/log.h\"\n> +\n> +using namespace libcamera;\n> +\n> +LOG_DECLARE_CATEGORY(HAL)\n> +\n> +namespace {\n> +\n> +/*\n> + * \\var camera3Resolutions\n> + * \\brief The list of image resolutions defined as mandatory to be supported by\n> + * the Android Camera3 specification\n> + */\n> +const std::vector<Size> camera3Resolutions = {\n> +\t{ 320, 240 },\n> +\t{ 640, 480 },\n> +\t{ 1280, 720 },\n> +\t{ 1920, 1080 }\n> +};\n> +\n> +/*\n> + * \\struct Camera3Format\n> + * \\brief Data associated with an Android format identifier\n> + * \\var libcameraFormats List of libcamera pixel formats compatible with the\n> + * Android format\n> + * \\var name The human-readable representation of the Android format code\n> + */\n> +struct Camera3Format {\n> +\tstd::vector<PixelFormat> libcameraFormats;\n> +\tbool mandatory;\n> +\tconst char *name;\n> +};\n> +\n> +/*\n> + * \\var camera3FormatsMap\n> + * \\brief Associate Android format code with ancillary data\n> + */\n> +const std::map<int, const Camera3Format> camera3FormatsMap = {\n> +\t{\n> +\t\tHAL_PIXEL_FORMAT_BLOB, {\n> +\t\t\t{ formats::MJPEG },\n> +\t\t\ttrue,\n> +\t\t\t\"BLOB\"\n> +\t\t}\n> +\t}, {\n> +\t\tHAL_PIXEL_FORMAT_YCbCr_420_888, {\n> +\t\t\t{ formats::NV12, formats::NV21 },\n> +\t\t\ttrue,\n> +\t\t\t\"YCbCr_420_888\"\n> +\t\t}\n> +\t}, {\n> +\t\t/*\n> +\t\t * \\todo Translate IMPLEMENTATION_DEFINED inspecting the gralloc\n> +\t\t * usage flag. For now, copy the YCbCr_420 configuration.\n> +\t\t */\n> +\t\tHAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, {\n> +\t\t\t{ formats::NV12, formats::NV21 },\n> +\t\t\ttrue,\n> +\t\t\t\"IMPLEMENTATION_DEFINED\"\n> +\t\t}\n> +\t}, {\n> +\t\tHAL_PIXEL_FORMAT_RAW10, {\n> +\t\t\t{\n> +\t\t\t\tformats::SBGGR10_CSI2P,\n> +\t\t\t\tformats::SGBRG10_CSI2P,\n> +\t\t\t\tformats::SGRBG10_CSI2P,\n> +\t\t\t\tformats::SRGGB10_CSI2P\n> +\t\t\t},\n> +\t\t\tfalse,\n> +\t\t\t\"RAW10\"\n> +\t\t}\n> +\t}, {\n> +\t\tHAL_PIXEL_FORMAT_RAW12, {\n> +\t\t\t{\n> +\t\t\t\tformats::SBGGR12_CSI2P,\n> +\t\t\t\tformats::SGBRG12_CSI2P,\n> +\t\t\t\tformats::SGRBG12_CSI2P,\n> +\t\t\t\tformats::SRGGB12_CSI2P\n> +\t\t\t},\n> +\t\t\tfalse,\n> +\t\t\t\"RAW12\"\n> +\t\t}\n> +\t}, {\n> +\t\tHAL_PIXEL_FORMAT_RAW16, {\n> +\t\t\t{\n> +\t\t\t\tformats::SBGGR16,\n> +\t\t\t\tformats::SGBRG16,\n> +\t\t\t\tformats::SGRBG16,\n> +\t\t\t\tformats::SRGGB16\n> +\t\t\t},\n> +\t\t\tfalse,\n> +\t\t\t\"RAW16\"\n> +\t\t}\n> +\t},\n> +};\n> +\n> +} /* namespace */\n> +\n> +int CameraCapabilities::initialize(std::shared_ptr<libcamera::Camera> camera,\n> +\t\t\t\t   int orientation, int facing)\n> +{\n> +\tcamera_ = camera;\n> +\torientation_ = orientation;\n> +\tfacing_ = facing;\n> +\n> +\t/* Acquire the camera and initialize available stream configurations. */\n> +\tint ret = camera_->acquire();\n> +\tif (ret) {\n> +\t\tLOG(HAL, Error) << \"Failed to temporarily acquire the camera\";\n> +\t\treturn ret;\n> +\t}\n> +\n> +\tret = initializeStreamConfigurations();\n> +\tcamera_->release();\n> +\tif (ret)\n> +\t\treturn ret;\n> +\n> +\treturn initializeStaticMetadata();\n> +}\n> +\n> +std::vector<Size> CameraCapabilities::getYUVResolutions(CameraConfiguration *cameraConfig,\n> +\t\t\t\t\t\t\tconst PixelFormat &pixelFormat,\n> +\t\t\t\t\t\t\tconst std::vector<Size> &resolutions)\n> +{\n> +\tstd::vector<Size> supportedResolutions;\n> +\n> +\tStreamConfiguration &cfg = cameraConfig->at(0);\n> +\tfor (const Size &res : resolutions) {\n> +\t\tcfg.pixelFormat = pixelFormat;\n> +\t\tcfg.size = res;\n> +\n> +\t\tCameraConfiguration::Status status = cameraConfig->validate();\n> +\t\tif (status != CameraConfiguration::Valid) {\n> +\t\t\tLOG(HAL, Debug) << cfg.toString() << \" not supported\";\n> +\t\t\tcontinue;\n> +\t\t}\n> +\n> +\t\tLOG(HAL, Debug) << cfg.toString() << \" supported\";\n> +\n> +\t\tsupportedResolutions.push_back(res);\n> +\t}\n> +\n> +\treturn supportedResolutions;\n> +}\n> +\n> +std::vector<Size> CameraCapabilities::getRawResolutions(const libcamera::PixelFormat &pixelFormat)\n> +{\n> +\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> +\t\tcamera_->generateConfiguration({ StreamRole::Raw });\n> +\tStreamConfiguration &cfg = cameraConfig->at(0);\n> +\tconst StreamFormats &formats = cfg.formats();\n> +\tstd::vector<Size> supportedResolutions = formats.sizes(pixelFormat);\n> +\n> +\treturn supportedResolutions;\n> +}\n> +\n> +/*\n> + * Initialize the format conversion map to translate from Android format\n> + * identifier to libcamera pixel formats and fill in the list of supported\n> + * stream configurations to be reported to the Android camera framework through\n> + * the Camera static metadata.\n> + */\n> +int CameraCapabilities::initializeStreamConfigurations()\n> +{\n> +\t/*\n> +\t * Get the maximum output resolutions\n> +\t * \\todo Get this from the camera properties once defined\n> +\t */\n> +\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> +\t\tcamera_->generateConfiguration({ StillCapture });\n> +\tif (!cameraConfig) {\n> +\t\tLOG(HAL, Error) << \"Failed to get maximum resolution\";\n> +\t\treturn -EINVAL;\n> +\t}\n> +\tStreamConfiguration &cfg = cameraConfig->at(0);\n> +\n> +\t/*\n> +\t * \\todo JPEG - Adjust the maximum available resolution by taking the\n> +\t * JPEG encoder requirements into account (alignment and aspect ratio).\n> +\t */\n> +\tconst Size maxRes = cfg.size;\n> +\tLOG(HAL, Debug) << \"Maximum supported resolution: \" << maxRes.toString();\n> +\n> +\t/*\n> +\t * Build the list of supported image resolutions.\n> +\t *\n> +\t * The resolutions listed in camera3Resolution are mandatory to be\n> +\t * supported, up to the camera maximum resolution.\n> +\t *\n> +\t * Augment the list by adding resolutions calculated from the camera\n> +\t * maximum one.\n> +\t */\n> +\tstd::vector<Size> cameraResolutions;\n> +\tstd::copy_if(camera3Resolutions.begin(), camera3Resolutions.end(),\n> +\t\t     std::back_inserter(cameraResolutions),\n> +\t\t     [&](const Size &res) { return res < maxRes; });\n> +\n> +\t/*\n> +\t * The Camera3 specification suggests adding 1/2 and 1/4 of the maximum\n> +\t * resolution.\n> +\t */\n> +\tfor (unsigned int divider = 2;; divider <<= 1) {\n> +\t\tSize derivedSize{\n> +\t\t\tmaxRes.width / divider,\n> +\t\t\tmaxRes.height / divider,\n> +\t\t};\n> +\n> +\t\tif (derivedSize.width < 320 ||\n> +\t\t    derivedSize.height < 240)\n> +\t\t\tbreak;\n> +\n> +\t\tcameraResolutions.push_back(derivedSize);\n> +\t}\n> +\tcameraResolutions.push_back(maxRes);\n> +\n> +\t/* Remove duplicated entries from the list of supported resolutions. */\n> +\tstd::sort(cameraResolutions.begin(), cameraResolutions.end());\n> +\tauto last = std::unique(cameraResolutions.begin(), cameraResolutions.end());\n> +\tcameraResolutions.erase(last, cameraResolutions.end());\n> +\n> +\t/*\n> +\t * Build the list of supported camera formats.\n> +\t *\n> +\t * To each Android format a list of compatible libcamera formats is\n> +\t * associated. The first libcamera format that tests successful is added\n> +\t * to the format translation map used when configuring the streams.\n> +\t * It is then tested against the list of supported camera resolutions to\n> +\t * build the stream configuration map reported through the camera static\n> +\t * metadata.\n> +\t */\n> +\tSize maxJpegSize;\n> +\tfor (const auto &format : camera3FormatsMap) {\n> +\t\tint androidFormat = format.first;\n> +\t\tconst Camera3Format &camera3Format = format.second;\n> +\t\tconst std::vector<PixelFormat> &libcameraFormats =\n> +\t\t\tcamera3Format.libcameraFormats;\n> +\n> +\t\tLOG(HAL, Debug) << \"Trying to map Android format \"\n> +\t\t\t\t<< camera3Format.name;\n> +\n> +\t\t/*\n> +\t\t * JPEG is always supported, either produced directly by the\n> +\t\t * camera, or encoded in the HAL.\n> +\t\t */\n> +\t\tif (androidFormat == HAL_PIXEL_FORMAT_BLOB) {\n> +\t\t\tformatsMap_[androidFormat] = formats::MJPEG;\n> +\t\t\tLOG(HAL, Debug) << \"Mapped Android format \"\n> +\t\t\t\t\t<< camera3Format.name << \" to \"\n> +\t\t\t\t\t<< formats::MJPEG.toString()\n> +\t\t\t\t\t<< \" (fixed mapping)\";\n> +\t\t\tcontinue;\n> +\t\t}\n> +\n> +\t\t/*\n> +\t\t * Test the libcamera formats that can produce images\n> +\t\t * compatible with the format defined by Android.\n> +\t\t */\n> +\t\tPixelFormat mappedFormat;\n> +\t\tfor (const PixelFormat &pixelFormat : libcameraFormats) {\n> +\n> +\t\t\tLOG(HAL, Debug) << \"Testing \" << pixelFormat.toString();\n> +\n> +\t\t\t/*\n> +\t\t\t * The stream configuration size can be adjusted,\n> +\t\t\t * not the pixel format.\n> +\t\t\t *\n> +\t\t\t * \\todo This could be simplified once all pipeline\n> +\t\t\t * handlers will report the StreamFormats list of\n> +\t\t\t * supported formats.\n> +\t\t\t */\n> +\t\t\tcfg.pixelFormat = pixelFormat;\n> +\n> +\t\t\tCameraConfiguration::Status status = cameraConfig->validate();\n> +\t\t\tif (status != CameraConfiguration::Invalid &&\n> +\t\t\t    cfg.pixelFormat == pixelFormat) {\n> +\t\t\t\tmappedFormat = pixelFormat;\n> +\t\t\t\tbreak;\n> +\t\t\t}\n> +\t\t}\n> +\n> +\t\tif (!mappedFormat.isValid()) {\n> +\t\t\t/* If the format is not mandatory, skip it. */\n> +\t\t\tif (!camera3Format.mandatory)\n> +\t\t\t\tcontinue;\n> +\n> +\t\t\tLOG(HAL, Error)\n> +\t\t\t\t<< \"Failed to map mandatory Android format \"\n> +\t\t\t\t<< camera3Format.name << \" (\"\n> +\t\t\t\t<< utils::hex(androidFormat) << \"): aborting\";\n> +\t\t\treturn -EINVAL;\n> +\t\t}\n> +\n> +\t\t/*\n> +\t\t * Record the mapping and then proceed to generate the\n> +\t\t * stream configurations map, by testing the image resolutions.\n> +\t\t */\n> +\t\tformatsMap_[androidFormat] = mappedFormat;\n> +\t\tLOG(HAL, Debug) << \"Mapped Android format \"\n> +\t\t\t\t<< camera3Format.name << \" to \"\n> +\t\t\t\t<< mappedFormat.toString();\n> +\n> +\t\tstd::vector<Size> resolutions;\n> +\t\tconst PixelFormatInfo &info = PixelFormatInfo::info(mappedFormat);\n> +\t\tif (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW)\n> +\t\t\tresolutions = getRawResolutions(mappedFormat);\n> +\t\telse\n> +\t\t\tresolutions = getYUVResolutions(cameraConfig.get(),\n> +\t\t\t\t\t\t\tmappedFormat,\n> +\t\t\t\t\t\t\tcameraResolutions);\n> +\n> +\t\tfor (const Size &res : resolutions) {\n> +\t\t\tstreamConfigurations_.push_back({ res, androidFormat });\n> +\n> +\t\t\t/*\n> +\t\t\t * If the format is HAL_PIXEL_FORMAT_YCbCr_420_888\n> +\t\t\t * from which JPEG is produced, add an entry for\n> +\t\t\t * the JPEG stream.\n> +\t\t\t *\n> +\t\t\t * \\todo Wire the JPEG encoder to query the supported\n> +\t\t\t * sizes provided a list of formats it can encode.\n> +\t\t\t *\n> +\t\t\t * \\todo Support JPEG streams produced by the Camera\n> +\t\t\t * natively.\n> +\t\t\t */\n> +\t\t\tif (androidFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {\n> +\t\t\t\tstreamConfigurations_.push_back(\n> +\t\t\t\t\t{ res, HAL_PIXEL_FORMAT_BLOB });\n> +\t\t\t\tmaxJpegSize = std::max(maxJpegSize, res);\n> +\t\t\t}\n> +\t\t}\n> +\n> +\t\t/*\n> +\t\t * \\todo Calculate the maximum JPEG buffer size by asking the\n> +\t\t * encoder giving the maximum frame size required.\n> +\t\t */\n> +\t\tmaxJpegBufferSize_ = maxJpegSize.width * maxJpegSize.height * 1.5;\n> +\t}\n> +\n> +\tLOG(HAL, Debug) << \"Collected stream configuration map: \";\n> +\tfor (const auto &entry : streamConfigurations_)\n> +\t\tLOG(HAL, Debug) << \"{ \" << entry.resolution.toString() << \" - \"\n> +\t\t\t\t<< utils::hex(entry.androidFormat) << \" }\";\n> +\n> +\treturn 0;\n> +}\n> +\n> +int CameraCapabilities::initializeStaticMetadata()\n> +{\n> +\tstaticMetadata_ = std::make_unique<CameraMetadata>(64, 1024);\n> +\tif (!staticMetadata_->isValid()) {\n> +\t\tLOG(HAL, Error) << \"Failed to allocate static metadata\";\n> +\t\tstaticMetadata_.reset();\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tconst ControlInfoMap &controlsInfo = camera_->controls();\n> +\tconst ControlList &properties = camera_->properties();\n> +\n> +\t/* Color correction static metadata. */\n> +\t{\n> +\t\tstd::vector<uint8_t> data;\n> +\t\tdata.reserve(3);\n> +\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::ColorCorrectionAberrationMode);\n> +\t\tif (infoMap != controlsInfo.end()) {\n> +\t\t\tfor (const auto &value : infoMap->second.values())\n> +\t\t\t\tdata.push_back(value.get<int32_t>());\n> +\t\t} else {\n> +\t\t\tdata.push_back(ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF);\n> +\t\t}\n> +\t\tstaticMetadata_->addEntry(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,\n> +\t\t\t\t\t  data);\n> +\t}\n> +\n> +\t/* Control static metadata. */\n> +\tstd::vector<uint8_t> aeAvailableAntiBandingModes = {\n> +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF,\n> +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ,\n> +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ,\n> +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,\n> +\t\t\t\t  aeAvailableAntiBandingModes);\n> +\n> +\tstd::vector<uint8_t> aeAvailableModes = {\n> +\t\tANDROID_CONTROL_AE_MODE_ON,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_MODES,\n> +\t\t\t\t  aeAvailableModes);\n> +\n> +\tint64_t minFrameDurationNsec = -1;\n> +\tint64_t maxFrameDurationNsec = -1;\n> +\tconst auto frameDurationsInfo = controlsInfo.find(&controls::FrameDurationLimits);\n> +\tif (frameDurationsInfo != controlsInfo.end()) {\n> +\t\tminFrameDurationNsec = frameDurationsInfo->second.min().get<int64_t>() * 1000;\n> +\t\tmaxFrameDurationNsec = frameDurationsInfo->second.max().get<int64_t>() * 1000;\n> +\n> +\t\t/*\n> +\t\t * Adjust the minimum frame duration to comply with Android\n> +\t\t * requirements. The camera service mandates all preview/record\n> +\t\t * streams to have a minimum frame duration < 33,366 milliseconds\n> +\t\t * (see MAX_PREVIEW_RECORD_DURATION_NS in the camera service\n> +\t\t * implementation).\n> +\t\t *\n> +\t\t * If we're close enough (+ 500 useconds) to that value, round\n> +\t\t * the minimum frame duration of the camera to an accepted\n> +\t\t * value.\n> +\t\t */\n> +\t\tstatic constexpr int64_t MAX_PREVIEW_RECORD_DURATION_NS = 1e9 / 29.97;\n> +\t\tif (minFrameDurationNsec > MAX_PREVIEW_RECORD_DURATION_NS &&\n> +\t\t    minFrameDurationNsec < MAX_PREVIEW_RECORD_DURATION_NS + 500000)\n> +\t\t\tminFrameDurationNsec = MAX_PREVIEW_RECORD_DURATION_NS - 1000;\n> +\n> +\t\t/*\n> +\t\t * The AE routine frame rate limits are computed using the frame\n> +\t\t * duration limits, as libcamera clips the AE routine to the\n> +\t\t * frame durations.\n> +\t\t */\n> +\t\tint32_t maxFps = std::round(1e9 / minFrameDurationNsec);\n> +\t\tint32_t minFps = std::round(1e9 / maxFrameDurationNsec);\n> +\t\tminFps = std::max(1, minFps);\n> +\n> +\t\t/*\n> +\t\t * Force rounding errors so that we have the proper frame\n> +\t\t * durations for when we reuse these variables later\n> +\t\t */\n> +\t\tminFrameDurationNsec = 1e9 / maxFps;\n> +\t\tmaxFrameDurationNsec = 1e9 / minFps;\n> +\n> +\t\t/*\n> +\t\t * Register to the camera service {min, max} and {max, max}\n> +\t\t * intervals as requested by the metadata documentation.\n> +\t\t */\n> +\t\tint32_t availableAeFpsTarget[] = {\n> +\t\t\tminFps, maxFps, maxFps, maxFps\n> +\t\t};\n> +\t\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> +\t\t\t\t\t  availableAeFpsTarget);\n> +\t}\n> +\n> +\tstd::vector<int32_t> aeCompensationRange = {\n> +\t\t0, 0,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_RANGE,\n> +\t\t\t\t  aeCompensationRange);\n> +\n> +\tconst camera_metadata_rational_t aeCompensationStep[] = {\n> +\t\t{ 0, 1 }\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_STEP,\n> +\t\t\t\t  aeCompensationStep);\n> +\n> +\tstd::vector<uint8_t> availableAfModes = {\n> +\t\tANDROID_CONTROL_AF_MODE_OFF,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AF_AVAILABLE_MODES,\n> +\t\t\t\t  availableAfModes);\n> +\n> +\tstd::vector<uint8_t> availableEffects = {\n> +\t\tANDROID_CONTROL_EFFECT_MODE_OFF,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_EFFECTS,\n> +\t\t\t\t  availableEffects);\n> +\n> +\tstd::vector<uint8_t> availableSceneModes = {\n> +\t\tANDROID_CONTROL_SCENE_MODE_DISABLED,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_SCENE_MODES,\n> +\t\t\t\t  availableSceneModes);\n> +\n> +\tstd::vector<uint8_t> availableStabilizationModes = {\n> +\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,\n> +\t\t\t\t  availableStabilizationModes);\n> +\n> +\t/*\n> +\t * \\todo Inspect the Camera capabilities to report the available\n> +\t * AWB modes. Default to AUTO as CTS tests require it.\n> +\t */\n> +\tstd::vector<uint8_t> availableAwbModes = {\n> +\t\tANDROID_CONTROL_AWB_MODE_AUTO,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AWB_AVAILABLE_MODES,\n> +\t\t\t\t  availableAwbModes);\n> +\n> +\tstd::vector<int32_t> availableMaxRegions = {\n> +\t\t0, 0, 0,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_MAX_REGIONS,\n> +\t\t\t\t  availableMaxRegions);\n> +\n> +\tstd::vector<uint8_t> sceneModesOverride = {\n> +\t\tANDROID_CONTROL_AE_MODE_ON,\n> +\t\tANDROID_CONTROL_AWB_MODE_AUTO,\n> +\t\tANDROID_CONTROL_AF_MODE_OFF,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_SCENE_MODE_OVERRIDES,\n> +\t\t\t\t  sceneModesOverride);\n> +\n> +\tuint8_t aeLockAvailable = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE;\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE,\n> +\t\t\t\t  aeLockAvailable);\n> +\n> +\tuint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> +\t\t\t\t  awbLockAvailable);\n> +\n> +\tchar availableControlModes = ANDROID_CONTROL_MODE_AUTO;\n> +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_MODES,\n> +\t\t\t\t  availableControlModes);\n> +\n> +\t/* JPEG static metadata. */\n> +\n> +\t/*\n> +\t * Create the list of supported thumbnail sizes by inspecting the\n> +\t * available JPEG resolutions collected in streamConfigurations_ and\n> +\t * generate one entry for each aspect ratio.\n> +\t *\n> +\t * The JPEG thumbnailer can freely scale, so pick an arbitrary\n> +\t * (160, 160) size as the bounding rectangle, which is then cropped to\n> +\t * the different supported aspect ratios.\n> +\t */\n> +\tconstexpr Size maxJpegThumbnail(160, 160);\n> +\tstd::vector<Size> thumbnailSizes;\n> +\tthumbnailSizes.push_back({ 0, 0 });\n> +\tfor (const auto &entry : streamConfigurations_) {\n> +\t\tif (entry.androidFormat != HAL_PIXEL_FORMAT_BLOB)\n> +\t\t\tcontinue;\n> +\n> +\t\tSize thumbnailSize = maxJpegThumbnail\n> +\t\t\t\t     .boundedToAspectRatio({ entry.resolution.width,\n> +\t\t\t\t\t\t\t     entry.resolution.height });\n> +\t\tthumbnailSizes.push_back(thumbnailSize);\n> +\t}\n> +\n> +\tstd::sort(thumbnailSizes.begin(), thumbnailSizes.end());\n> +\tauto last = std::unique(thumbnailSizes.begin(), thumbnailSizes.end());\n> +\tthumbnailSizes.erase(last, thumbnailSizes.end());\n> +\n> +\t/* Transform sizes in to a list of integers that can be consumed. */\n> +\tstd::vector<int32_t> thumbnailEntries;\n> +\tthumbnailEntries.reserve(thumbnailSizes.size() * 2);\n> +\tfor (const auto &size : thumbnailSizes) {\n> +\t\tthumbnailEntries.push_back(size.width);\n> +\t\tthumbnailEntries.push_back(size.height);\n> +\t}\n> +\tstaticMetadata_->addEntry(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,\n> +\t\t\t\t  thumbnailEntries);\n> +\n> +\tstaticMetadata_->addEntry(ANDROID_JPEG_MAX_SIZE, maxJpegBufferSize_);\n> +\n> +\t/* Sensor static metadata. */\n> +\tstd::array<int32_t, 2> pixelArraySize;\n> +\t{\n> +\t\tconst Size &size = properties.get(properties::PixelArraySize);\n> +\t\tpixelArraySize[0] = size.width;\n> +\t\tpixelArraySize[1] = size.height;\n> +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,\n> +\t\t\t\t\t  pixelArraySize);\n> +\t}\n> +\n> +\tif (properties.contains(properties::UnitCellSize)) {\n> +\t\tconst Size &cellSize = properties.get<Size>(properties::UnitCellSize);\n> +\t\tstd::array<float, 2> physicalSize{\n> +\t\t\tcellSize.width * pixelArraySize[0] / 1e6f,\n> +\t\t\tcellSize.height * pixelArraySize[1] / 1e6f\n> +\t\t};\n> +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,\n> +\t\t\t\t\t  physicalSize);\n> +\t}\n> +\n> +\t{\n> +\t\tconst Span<const Rectangle> &rects =\n> +\t\t\tproperties.get(properties::PixelArrayActiveAreas);\n> +\t\tstd::vector<int32_t> data{\n> +\t\t\tstatic_cast<int32_t>(rects[0].x),\n> +\t\t\tstatic_cast<int32_t>(rects[0].y),\n> +\t\t\tstatic_cast<int32_t>(rects[0].width),\n> +\t\t\tstatic_cast<int32_t>(rects[0].height),\n> +\t\t};\n> +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,\n> +\t\t\t\t\t  data);\n> +\t}\n> +\n> +\tint32_t sensitivityRange[] = {\n> +\t\t32, 2400,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,\n> +\t\t\t\t  sensitivityRange);\n> +\n> +\t/* Report the color filter arrangement if the camera reports it. */\n> +\tif (properties.contains(properties::draft::ColorFilterArrangement)) {\n> +\t\tuint8_t filterArr = properties.get(properties::draft::ColorFilterArrangement);\n> +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,\n> +\t\t\t\t\t  filterArr);\n> +\t}\n> +\n> +\tconst auto &exposureInfo = controlsInfo.find(&controls::ExposureTime);\n> +\tif (exposureInfo != controlsInfo.end()) {\n> +\t\tint64_t exposureTimeRange[2] = {\n> +\t\t\texposureInfo->second.min().get<int32_t>() * 1000LL,\n> +\t\t\texposureInfo->second.max().get<int32_t>() * 1000LL,\n> +\t\t};\n> +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,\n> +\t\t\t\t\t  exposureTimeRange, 2);\n> +\t}\n> +\n> +\tstaticMetadata_->addEntry(ANDROID_SENSOR_ORIENTATION, orientation_);\n> +\n> +\tstd::vector<int32_t> testPatternModes = {\n> +\t\tANDROID_SENSOR_TEST_PATTERN_MODE_OFF\n> +\t};\n> +\tconst auto &testPatternsInfo =\n> +\t\tcontrolsInfo.find(&controls::draft::TestPatternMode);\n> +\tif (testPatternsInfo != controlsInfo.end()) {\n> +\t\tconst auto &values = testPatternsInfo->second.values();\n> +\t\tASSERT(!values.empty());\n> +\t\tfor (const auto &value : values) {\n> +\t\t\tswitch (value.get<int32_t>()) {\n> +\t\t\tcase controls::draft::TestPatternModeOff:\n> +\t\t\t\t/*\n> +\t\t\t\t * ANDROID_SENSOR_TEST_PATTERN_MODE_OFF is\n> +\t\t\t\t * already in testPatternModes.\n> +\t\t\t\t */\n> +\t\t\t\tbreak;\n> +\n> +\t\t\tcase controls::draft::TestPatternModeSolidColor:\n> +\t\t\t\ttestPatternModes.push_back(\n> +\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR);\n> +\t\t\t\tbreak;\n> +\n> +\t\t\tcase controls::draft::TestPatternModeColorBars:\n> +\t\t\t\ttestPatternModes.push_back(\n> +\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS);\n> +\t\t\t\tbreak;\n> +\n> +\t\t\tcase controls::draft::TestPatternModeColorBarsFadeToGray:\n> +\t\t\t\ttestPatternModes.push_back(\n> +\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY);\n> +\t\t\t\tbreak;\n> +\n> +\t\t\tcase controls::draft::TestPatternModePn9:\n> +\t\t\t\ttestPatternModes.push_back(\n> +\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_PN9);\n> +\t\t\t\tbreak;\n> +\n> +\t\t\tcase controls::draft::TestPatternModeCustom1:\n> +\t\t\t\t/* We don't support this yet. */\n> +\t\t\t\tbreak;\n> +\n> +\t\t\tdefault:\n> +\t\t\t\tLOG(HAL, Error) << \"Unknown test pattern mode: \"\n> +\t\t\t\t\t\t<< value.get<int32_t>();\n> +\t\t\t\tcontinue;\n> +\t\t\t}\n> +\t\t}\n> +\t}\n> +\tstaticMetadata_->addEntry(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,\n> +\t\t\t\t  testPatternModes);\n> +\n> +\tuint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;\n> +\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,\n> +\t\t\t\t  timestampSource);\n> +\n> +\tif (maxFrameDurationNsec > 0)\n> +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,\n> +\t\t\t\t\t  maxFrameDurationNsec);\n> +\n> +\t/* Statistics static metadata. */\n> +\tuint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;\n> +\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,\n> +\t\t\t\t  faceDetectMode);\n> +\n> +\tint32_t maxFaceCount = 0;\n> +\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,\n> +\t\t\t\t  maxFaceCount);\n> +\n> +\t{\n> +\t\tstd::vector<uint8_t> data;\n> +\t\tdata.reserve(2);\n> +\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::LensShadingMapMode);\n> +\t\tif (infoMap != controlsInfo.end()) {\n> +\t\t\tfor (const auto &value : infoMap->second.values())\n> +\t\t\t\tdata.push_back(value.get<int32_t>());\n> +\t\t} else {\n> +\t\t\tdata.push_back(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF);\n> +\t\t}\n> +\t\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,\n> +\t\t\t\t\t  data);\n> +\t}\n> +\n> +\t/* Sync static metadata. */\n> +\tint32_t maxLatency = ANDROID_SYNC_MAX_LATENCY_UNKNOWN;\n> +\tstaticMetadata_->addEntry(ANDROID_SYNC_MAX_LATENCY, maxLatency);\n> +\n> +\t/* Flash static metadata. */\n> +\tchar flashAvailable = ANDROID_FLASH_INFO_AVAILABLE_FALSE;\n> +\tstaticMetadata_->addEntry(ANDROID_FLASH_INFO_AVAILABLE,\n> +\t\t\t\t  flashAvailable);\n> +\n> +\t/* Lens static metadata. */\n> +\tstd::vector<float> lensApertures = {\n> +\t\t2.53 / 100,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_APERTURES,\n> +\t\t\t\t  lensApertures);\n> +\n> +\tuint8_t lensFacing;\n> +\tswitch (facing_) {\n> +\tdefault:\n> +\tcase CAMERA_FACING_FRONT:\n> +\t\tlensFacing = ANDROID_LENS_FACING_FRONT;\n> +\t\tbreak;\n> +\tcase CAMERA_FACING_BACK:\n> +\t\tlensFacing = ANDROID_LENS_FACING_BACK;\n> +\t\tbreak;\n> +\tcase CAMERA_FACING_EXTERNAL:\n> +\t\tlensFacing = ANDROID_LENS_FACING_EXTERNAL;\n> +\t\tbreak;\n> +\t}\n> +\tstaticMetadata_->addEntry(ANDROID_LENS_FACING, lensFacing);\n> +\n> +\tstd::vector<float> lensFocalLengths = {\n> +\t\t1,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,\n> +\t\t\t\t  lensFocalLengths);\n> +\n> +\tstd::vector<uint8_t> opticalStabilizations = {\n> +\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,\n> +\t\t\t\t  opticalStabilizations);\n> +\n> +\tfloat hypeFocalDistance = 0;\n> +\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,\n> +\t\t\t\t  hypeFocalDistance);\n> +\n> +\tfloat minFocusDistance = 0;\n> +\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,\n> +\t\t\t\t  minFocusDistance);\n> +\n> +\t/* Noise reduction modes. */\n> +\t{\n> +\t\tstd::vector<uint8_t> data;\n> +\t\tdata.reserve(5);\n> +\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::NoiseReductionMode);\n> +\t\tif (infoMap != controlsInfo.end()) {\n> +\t\t\tfor (const auto &value : infoMap->second.values())\n> +\t\t\t\tdata.push_back(value.get<int32_t>());\n> +\t\t} else {\n> +\t\t\tdata.push_back(ANDROID_NOISE_REDUCTION_MODE_OFF);\n> +\t\t}\n> +\t\tstaticMetadata_->addEntry(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,\n> +\t\t\t\t\t  data);\n> +\t}\n> +\n> +\t/* Scaler static metadata. */\n> +\n> +\t/*\n> +\t * \\todo The digital zoom factor is a property that depends on the\n> +\t * desired output configuration and the sensor frame size input to the\n> +\t * ISP. This information is not available to the Android HAL, not at\n> +\t * initialization time at least.\n> +\t *\n> +\t * As a workaround rely on pipeline handlers initializing the\n> +\t * ScalerCrop control with the camera default configuration and use the\n> +\t * maximum and minimum crop rectangles to calculate the digital zoom\n> +\t * factor.\n> +\t */\n> +\tfloat maxZoom = 1.0f;\n> +\tconst auto scalerCrop = controlsInfo.find(&controls::ScalerCrop);\n> +\tif (scalerCrop != controlsInfo.end()) {\n> +\t\tRectangle min = scalerCrop->second.min().get<Rectangle>();\n> +\t\tRectangle max = scalerCrop->second.max().get<Rectangle>();\n> +\t\tmaxZoom = std::min(1.0f * max.width / min.width,\n> +\t\t\t\t   1.0f * max.height / min.height);\n> +\t}\n> +\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,\n> +\t\t\t\t  maxZoom);\n> +\n> +\tstd::vector<uint32_t> availableStreamConfigurations;\n> +\tavailableStreamConfigurations.reserve(streamConfigurations_.size() * 4);\n> +\tfor (const auto &entry : streamConfigurations_) {\n> +\t\tavailableStreamConfigurations.push_back(entry.androidFormat);\n> +\t\tavailableStreamConfigurations.push_back(entry.resolution.width);\n> +\t\tavailableStreamConfigurations.push_back(entry.resolution.height);\n> +\t\tavailableStreamConfigurations.push_back(\n> +\t\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);\n> +\t}\n> +\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,\n> +\t\t\t\t  availableStreamConfigurations);\n> +\n> +\tstd::vector<int64_t> availableStallDurations = {\n> +\t\tANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920, 33333333,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,\n> +\t\t\t\t  availableStallDurations);\n> +\n> +\t/* Use the minimum frame duration for all the YUV/RGB formats. */\n> +\tif (minFrameDurationNsec > 0) {\n> +\t\tstd::vector<int64_t> minFrameDurations;\n> +\t\tminFrameDurations.reserve(streamConfigurations_.size() * 4);\n> +\t\tfor (const auto &entry : streamConfigurations_) {\n> +\t\t\tminFrameDurations.push_back(entry.androidFormat);\n> +\t\t\tminFrameDurations.push_back(entry.resolution.width);\n> +\t\t\tminFrameDurations.push_back(entry.resolution.height);\n> +\t\t\tminFrameDurations.push_back(minFrameDurationNsec);\n> +\t\t}\n> +\t\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,\n> +\t\t\t\t\t  minFrameDurations);\n> +\t}\n> +\n> +\tuint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY;\n> +\tstaticMetadata_->addEntry(ANDROID_SCALER_CROPPING_TYPE, croppingType);\n> +\n> +\t/* Info static metadata. */\n> +\tuint8_t supportedHWLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;\n> +\tstaticMetadata_->addEntry(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,\n> +\t\t\t\t  supportedHWLevel);\n> +\n> +\t/* Request static metadata. */\n> +\tint32_t partialResultCount = 1;\n> +\tstaticMetadata_->addEntry(ANDROID_REQUEST_PARTIAL_RESULT_COUNT,\n> +\t\t\t\t  partialResultCount);\n> +\n> +\t{\n> +\t\t/* Default the value to 2 if not reported by the camera. */\n> +\t\tuint8_t maxPipelineDepth = 2;\n> +\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::PipelineDepth);\n> +\t\tif (infoMap != controlsInfo.end())\n> +\t\t\tmaxPipelineDepth = infoMap->second.max().get<int32_t>();\n> +\t\tstaticMetadata_->addEntry(ANDROID_REQUEST_PIPELINE_MAX_DEPTH,\n> +\t\t\t\t\t  maxPipelineDepth);\n> +\t}\n> +\n> +\t/* LIMITED does not support reprocessing. */\n> +\tuint32_t maxNumInputStreams = 0;\n> +\tstaticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,\n> +\t\t\t\t  maxNumInputStreams);\n> +\n> +\tstd::vector<uint8_t> availableCapabilities = {\n> +\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,\n> +\t};\n> +\n> +\t/* Report if camera supports RAW. */\n> +\tbool rawStreamAvailable = false;\n> +\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> +\t\tcamera_->generateConfiguration({ StreamRole::Raw });\n> +\tif (cameraConfig && !cameraConfig->empty()) {\n> +\t\tconst PixelFormatInfo &info =\n> +\t\t\tPixelFormatInfo::info(cameraConfig->at(0).pixelFormat);\n> +\t\t/* Only advertise RAW support if RAW16 is possible. */\n> +\t\tif (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW &&\n> +\t\t    info.bitsPerPixel == 16) {\n> +\t\t\trawStreamAvailable = true;\n> +\t\t\tavailableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);\n> +\t\t}\n> +\t}\n> +\n> +\t/* Number of { RAW, YUV, JPEG } supported output streams */\n> +\tint32_t numOutStreams[] = { rawStreamAvailable, 2, 1 };\n> +\tstaticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,\n> +\t\t\t\t  numOutStreams);\n> +\n> +\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CAPABILITIES,\n> +\t\t\t\t  availableCapabilities);\n> +\n> +\tstd::vector<int32_t> availableCharacteristicsKeys = {\n> +\t\tANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,\n> +\t\tANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,\n> +\t\tANDROID_CONTROL_AE_AVAILABLE_MODES,\n> +\t\tANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> +\t\tANDROID_CONTROL_AE_COMPENSATION_RANGE,\n> +\t\tANDROID_CONTROL_AE_COMPENSATION_STEP,\n> +\t\tANDROID_CONTROL_AE_LOCK_AVAILABLE,\n> +\t\tANDROID_CONTROL_AF_AVAILABLE_MODES,\n> +\t\tANDROID_CONTROL_AVAILABLE_EFFECTS,\n> +\t\tANDROID_CONTROL_AVAILABLE_MODES,\n> +\t\tANDROID_CONTROL_AVAILABLE_SCENE_MODES,\n> +\t\tANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,\n> +\t\tANDROID_CONTROL_AWB_AVAILABLE_MODES,\n> +\t\tANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> +\t\tANDROID_CONTROL_MAX_REGIONS,\n> +\t\tANDROID_CONTROL_SCENE_MODE_OVERRIDES,\n> +\t\tANDROID_FLASH_INFO_AVAILABLE,\n> +\t\tANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,\n> +\t\tANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,\n> +\t\tANDROID_JPEG_MAX_SIZE,\n> +\t\tANDROID_LENS_FACING,\n> +\t\tANDROID_LENS_INFO_AVAILABLE_APERTURES,\n> +\t\tANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,\n> +\t\tANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,\n> +\t\tANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,\n> +\t\tANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,\n> +\t\tANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,\n> +\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES,\n> +\t\tANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,\n> +\t\tANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,\n> +\t\tANDROID_REQUEST_PARTIAL_RESULT_COUNT,\n> +\t\tANDROID_REQUEST_PIPELINE_MAX_DEPTH,\n> +\t\tANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,\n> +\t\tANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,\n> +\t\tANDROID_SCALER_AVAILABLE_STALL_DURATIONS,\n> +\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,\n> +\t\tANDROID_SCALER_CROPPING_TYPE,\n> +\t\tANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,\n> +\t\tANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,\n> +\t\tANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,\n> +\t\tANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,\n> +\t\tANDROID_SENSOR_INFO_MAX_FRAME_DURATION,\n> +\t\tANDROID_SENSOR_INFO_PHYSICAL_SIZE,\n> +\t\tANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,\n> +\t\tANDROID_SENSOR_INFO_SENSITIVITY_RANGE,\n> +\t\tANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,\n> +\t\tANDROID_SENSOR_ORIENTATION,\n> +\t\tANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,\n> +\t\tANDROID_STATISTICS_INFO_MAX_FACE_COUNT,\n> +\t\tANDROID_SYNC_MAX_LATENCY,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,\n> +\t\t\t\t  availableCharacteristicsKeys);\n> +\n> +\tstd::vector<int32_t> availableRequestKeys = {\n> +\t\tANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> +\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> +\t\tANDROID_CONTROL_AE_LOCK,\n> +\t\tANDROID_CONTROL_AE_MODE,\n> +\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> +\t\tANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> +\t\tANDROID_CONTROL_AF_MODE,\n> +\t\tANDROID_CONTROL_AF_TRIGGER,\n> +\t\tANDROID_CONTROL_AWB_LOCK,\n> +\t\tANDROID_CONTROL_AWB_MODE,\n> +\t\tANDROID_CONTROL_CAPTURE_INTENT,\n> +\t\tANDROID_CONTROL_EFFECT_MODE,\n> +\t\tANDROID_CONTROL_MODE,\n> +\t\tANDROID_CONTROL_SCENE_MODE,\n> +\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE,\n> +\t\tANDROID_FLASH_MODE,\n> +\t\tANDROID_JPEG_ORIENTATION,\n> +\t\tANDROID_JPEG_QUALITY,\n> +\t\tANDROID_JPEG_THUMBNAIL_QUALITY,\n> +\t\tANDROID_JPEG_THUMBNAIL_SIZE,\n> +\t\tANDROID_LENS_APERTURE,\n> +\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> +\t\tANDROID_NOISE_REDUCTION_MODE,\n> +\t\tANDROID_SCALER_CROP_REGION,\n> +\t\tANDROID_STATISTICS_FACE_DETECT_MODE\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,\n> +\t\t\t\t  availableRequestKeys);\n> +\n> +\tstd::vector<int32_t> availableResultKeys = {\n> +\t\tANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> +\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> +\t\tANDROID_CONTROL_AE_LOCK,\n> +\t\tANDROID_CONTROL_AE_MODE,\n> +\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> +\t\tANDROID_CONTROL_AE_STATE,\n> +\t\tANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> +\t\tANDROID_CONTROL_AF_MODE,\n> +\t\tANDROID_CONTROL_AF_STATE,\n> +\t\tANDROID_CONTROL_AF_TRIGGER,\n> +\t\tANDROID_CONTROL_AWB_LOCK,\n> +\t\tANDROID_CONTROL_AWB_MODE,\n> +\t\tANDROID_CONTROL_AWB_STATE,\n> +\t\tANDROID_CONTROL_CAPTURE_INTENT,\n> +\t\tANDROID_CONTROL_EFFECT_MODE,\n> +\t\tANDROID_CONTROL_MODE,\n> +\t\tANDROID_CONTROL_SCENE_MODE,\n> +\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE,\n> +\t\tANDROID_FLASH_MODE,\n> +\t\tANDROID_FLASH_STATE,\n> +\t\tANDROID_JPEG_GPS_COORDINATES,\n> +\t\tANDROID_JPEG_GPS_PROCESSING_METHOD,\n> +\t\tANDROID_JPEG_GPS_TIMESTAMP,\n> +\t\tANDROID_JPEG_ORIENTATION,\n> +\t\tANDROID_JPEG_QUALITY,\n> +\t\tANDROID_JPEG_SIZE,\n> +\t\tANDROID_JPEG_THUMBNAIL_QUALITY,\n> +\t\tANDROID_JPEG_THUMBNAIL_SIZE,\n> +\t\tANDROID_LENS_APERTURE,\n> +\t\tANDROID_LENS_FOCAL_LENGTH,\n> +\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> +\t\tANDROID_LENS_STATE,\n> +\t\tANDROID_NOISE_REDUCTION_MODE,\n> +\t\tANDROID_REQUEST_PIPELINE_DEPTH,\n> +\t\tANDROID_SCALER_CROP_REGION,\n> +\t\tANDROID_SENSOR_EXPOSURE_TIME,\n> +\t\tANDROID_SENSOR_FRAME_DURATION,\n> +\t\tANDROID_SENSOR_ROLLING_SHUTTER_SKEW,\n> +\t\tANDROID_SENSOR_TEST_PATTERN_MODE,\n> +\t\tANDROID_SENSOR_TIMESTAMP,\n> +\t\tANDROID_STATISTICS_FACE_DETECT_MODE,\n> +\t\tANDROID_STATISTICS_LENS_SHADING_MAP_MODE,\n> +\t\tANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,\n> +\t\tANDROID_STATISTICS_SCENE_FLICKER,\n> +\t};\n> +\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,\n> +\t\t\t\t  availableResultKeys);\n> +\n> +\tif (!staticMetadata_->isValid()) {\n> +\t\tLOG(HAL, Error) << \"Failed to construct static metadata\";\n> +\t\tstaticMetadata_.reset();\n> +\t\treturn -EINVAL;\n> +\t}\n> +\n> +\tif (staticMetadata_->resized()) {\n> +\t\tauto [entryCount, dataCount] = staticMetadata_->usage();\n> +\t\tLOG(HAL, Info)\n> +\t\t\t<< \"Static metadata resized: \" << entryCount\n> +\t\t\t<< \" entries and \" << dataCount << \" bytes used\";\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n> +/* Translate Android format code to libcamera pixel format. */\n> +PixelFormat CameraCapabilities::toPixelFormat(int format) const\n> +{\n> +\tauto it = formatsMap_.find(format);\n> +\tif (it == formatsMap_.end()) {\n> +\t\tLOG(HAL, Error) << \"Requested format \" << utils::hex(format)\n> +\t\t\t\t<< \" not supported\";\n> +\t\treturn PixelFormat();\n> +\t}\n> +\n> +\treturn it->second;\n> +}\n> +\n> +std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplatePreview() const\n> +{\n> +\t/*\n> +\t * \\todo Keep this in sync with the actual number of entries.\n> +\t * Currently: 20 entries, 35 bytes\n> +\t */\n> +\tauto requestTemplate = std::make_unique<CameraMetadata>(21, 36);\n> +\tif (!requestTemplate->isValid()) {\n> +\t\treturn nullptr;\n> +\t}\n> +\n> +\t/* Get the FPS range registered in the static metadata. */\n> +\tcamera_metadata_ro_entry_t entry;\n> +\tbool found = staticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> +\t\t\t\t\t       &entry);\n> +\tif (!found) {\n> +\t\tLOG(HAL, Error) << \"Cannot create capture template without FPS range\";\n> +\t\treturn nullptr;\n> +\t}\n> +\n> +\t/*\n> +\t * Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata\n> +\t * has been assembled as {{min, max} {max, max}}.\n> +\t */\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> +\t\t\t\t  entry.data.i32, 2);\n> +\n> +\tuint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_MODE, aeMode);\n> +\n> +\tint32_t aeExposureCompensation = 0;\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> +\t\t\t\t  aeExposureCompensation);\n> +\n> +\tuint8_t aePrecaptureTrigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> +\t\t\t\t  aePrecaptureTrigger);\n> +\n> +\tuint8_t aeLock = ANDROID_CONTROL_AE_LOCK_OFF;\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_LOCK, aeLock);\n> +\n> +\tuint8_t aeAntibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> +\t\t\t\t  aeAntibandingMode);\n> +\n> +\tuint8_t afMode = ANDROID_CONTROL_AF_MODE_OFF;\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_AF_MODE, afMode);\n> +\n> +\tuint8_t afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_AF_TRIGGER, afTrigger);\n> +\n> +\tuint8_t awbMode = ANDROID_CONTROL_AWB_MODE_AUTO;\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_AWB_MODE, awbMode);\n> +\n> +\tuint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_AWB_LOCK, awbLock);\n> +\n> +\tuint8_t flashMode = ANDROID_FLASH_MODE_OFF;\n> +\trequestTemplate->addEntry(ANDROID_FLASH_MODE, flashMode);\n> +\n> +\tuint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;\n> +\trequestTemplate->addEntry(ANDROID_STATISTICS_FACE_DETECT_MODE,\n> +\t\t\t\t  faceDetectMode);\n> +\n> +\tuint8_t noiseReduction = ANDROID_NOISE_REDUCTION_MODE_OFF;\n> +\trequestTemplate->addEntry(ANDROID_NOISE_REDUCTION_MODE,\n> +\t\t\t\t  noiseReduction);\n> +\n> +\tuint8_t aberrationMode = ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF;\n> +\trequestTemplate->addEntry(ANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> +\t\t\t\t  aberrationMode);\n> +\n> +\tuint8_t controlMode = ANDROID_CONTROL_MODE_AUTO;\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_MODE, controlMode);\n> +\n> +\tfloat lensAperture = 2.53 / 100;\n> +\trequestTemplate->addEntry(ANDROID_LENS_APERTURE, lensAperture);\n> +\n> +\tuint8_t opticalStabilization = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;\n> +\trequestTemplate->addEntry(ANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> +\t\t\t\t  opticalStabilization);\n> +\n> +\tuint8_t captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;\n> +\trequestTemplate->addEntry(ANDROID_CONTROL_CAPTURE_INTENT,\n> +\t\t\t\t  captureIntent);\n> +\n> +\treturn requestTemplate;\n> +}\n> +\n> +std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplateVideo() const\n> +{\n> +\tstd::unique_ptr<CameraMetadata> previewTemplate = requestTemplatePreview();\n> +\tif (!previewTemplate)\n> +\t\treturn nullptr;\n> +\n> +\t/*\n> +\t * The video template requires a fixed FPS range. Everything else\n> +\t * stays the same as the preview template.\n> +\t */\n> +\tcamera_metadata_ro_entry_t entry;\n> +\tstaticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> +\t\t\t\t  &entry);\n> +\n> +\t/*\n> +\t * Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata\n> +\t * has been assembled as {{min, max} {max, max}}.\n> +\t */\n> +\tpreviewTemplate->updateEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> +\t\t\t\t     entry.data.i32 + 2, 2);\n> +\n> +\treturn previewTemplate;\n> +}\n> diff --git a/src/android/camera_capabilities.h b/src/android/camera_capabilities.h\n> new file mode 100644\n> index 000000000000..3a427e768aff\n> --- /dev/null\n> +++ b/src/android/camera_capabilities.h\n> @@ -0,0 +1,64 @@\n> +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> +/*\n> + * Copyright (C) 2021, Google Inc.\n> + *\n> + * camera_capabilities.h - Camera static properties manager\n> + */\n> +#ifndef __ANDROID_CAMERA_CAPABILITIES_H__\n> +#define __ANDROID_CAMERA_CAPABILITIES_H__\n> +\n> +#include <map>\n> +#include <memory>\n> +#include <vector>\n> +\n> +#include <libcamera/camera.h>\n> +#include <libcamera/class.h>\n> +#include <libcamera/geometry.h>\n> +\n> +#include \"camera_metadata.h\"\n> +\n> +class CameraCapabilities\n> +{\n> +public:\n> +\tCameraCapabilities() = default;\n> +\n> +\tint initialize(std::shared_ptr<libcamera::Camera> camera,\n> +\t\t       int orientation, int facing);\n> +\n> +\tCameraMetadata *staticMetadata() const { return staticMetadata_.get(); }\n> +\tlibcamera::PixelFormat toPixelFormat(int format) const;\n> +\tunsigned int maxJpegBufferSize() const { return maxJpegBufferSize_; }\n> +\n> +\tstd::unique_ptr<CameraMetadata> requestTemplatePreview() const;\n> +\tstd::unique_ptr<CameraMetadata> requestTemplateVideo() const;\n> +\n> +private:\n> +\tLIBCAMERA_DISABLE_COPY_AND_MOVE(CameraCapabilities)\n> +\n> +\tstruct Camera3StreamConfiguration {\n> +\t\tlibcamera::Size resolution;\n> +\t\tint androidFormat;\n> +\t};\n> +\n> +\tstd::vector<libcamera::Size>\n> +\tgetYUVResolutions(libcamera::CameraConfiguration *cameraConfig,\n> +\t\t\t  const libcamera::PixelFormat &pixelFormat,\n> +\t\t\t  const std::vector<libcamera::Size> &resolutions);\n> +\tstd::vector<libcamera::Size>\n> +\tgetRawResolutions(const libcamera::PixelFormat &pixelFormat);\n> +\tint initializeStreamConfigurations();\n> +\n> +\tint initializeStaticMetadata();\n> +\n> +\tstd::shared_ptr<libcamera::Camera> camera_;\n> +\n> +\tint facing_;\n> +\tint orientation_;\n> +\n> +\tstd::vector<Camera3StreamConfiguration> streamConfigurations_;\n> +\tstd::map<int, libcamera::PixelFormat> formatsMap_;\n> +\tstd::unique_ptr<CameraMetadata> staticMetadata_;\n> +\tunsigned int maxJpegBufferSize_;\n> +};\n> +\n> +#endif /* __ANDROID_CAMERA_CAPABILITIES_H__ */\n> diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp\n> index 8c71fd0675d3..4bd125d7020a 100644\n> --- a/src/android/camera_device.cpp\n> +++ b/src/android/camera_device.cpp\n> @@ -10,11 +10,8 @@\n>  #include \"camera_ops.h\"\n>  #include \"post_processor.h\"\n>  \n> -#include <array>\n> -#include <cmath>\n>  #include <fstream>\n>  #include <sys/mman.h>\n> -#include <tuple>\n>  #include <unistd.h>\n>  #include <vector>\n>  \n> @@ -23,7 +20,6 @@\n>  #include <libcamera/formats.h>\n>  #include <libcamera/property_ids.h>\n>  \n> -#include \"libcamera/internal/formats.h\"\n>  #include \"libcamera/internal/log.h\"\n>  #include \"libcamera/internal/thread.h\"\n>  #include \"libcamera/internal/utils.h\"\n> @@ -36,94 +32,6 @@ LOG_DECLARE_CATEGORY(HAL)\n>  \n>  namespace {\n>  \n> -/*\n> - * \\var camera3Resolutions\n> - * \\brief The list of image resolutions defined as mandatory to be supported by\n> - * the Android Camera3 specification\n> - */\n> -const std::vector<Size> camera3Resolutions = {\n> -\t{ 320, 240 },\n> -\t{ 640, 480 },\n> -\t{ 1280, 720 },\n> -\t{ 1920, 1080 }\n> -};\n> -\n> -/*\n> - * \\struct Camera3Format\n> - * \\brief Data associated with an Android format identifier\n> - * \\var libcameraFormats List of libcamera pixel formats compatible with the\n> - * Android format\n> - * \\var name The human-readable representation of the Android format code\n> - */\n> -struct Camera3Format {\n> -\tstd::vector<PixelFormat> libcameraFormats;\n> -\tbool mandatory;\n> -\tconst char *name;\n> -};\n> -\n> -/*\n> - * \\var camera3FormatsMap\n> - * \\brief Associate Android format code with ancillary data\n> - */\n> -const std::map<int, const Camera3Format> camera3FormatsMap = {\n> -\t{\n> -\t\tHAL_PIXEL_FORMAT_BLOB, {\n> -\t\t\t{ formats::MJPEG },\n> -\t\t\ttrue,\n> -\t\t\t\"BLOB\"\n> -\t\t}\n> -\t}, {\n> -\t\tHAL_PIXEL_FORMAT_YCbCr_420_888, {\n> -\t\t\t{ formats::NV12, formats::NV21 },\n> -\t\t\ttrue,\n> -\t\t\t\"YCbCr_420_888\"\n> -\t\t}\n> -\t}, {\n> -\t\t/*\n> -\t\t * \\todo Translate IMPLEMENTATION_DEFINED inspecting the gralloc\n> -\t\t * usage flag. For now, copy the YCbCr_420 configuration.\n> -\t\t */\n> -\t\tHAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, {\n> -\t\t\t{ formats::NV12, formats::NV21 },\n> -\t\t\ttrue,\n> -\t\t\t\"IMPLEMENTATION_DEFINED\"\n> -\t\t}\n> -\t}, {\n> -\t\tHAL_PIXEL_FORMAT_RAW10, {\n> -\t\t\t{\n> -\t\t\t\tformats::SBGGR10_CSI2P,\n> -\t\t\t\tformats::SGBRG10_CSI2P,\n> -\t\t\t\tformats::SGRBG10_CSI2P,\n> -\t\t\t\tformats::SRGGB10_CSI2P\n> -\t\t\t},\n> -\t\t\tfalse,\n> -\t\t\t\"RAW10\"\n> -\t\t}\n> -\t}, {\n> -\t\tHAL_PIXEL_FORMAT_RAW12, {\n> -\t\t\t{\n> -\t\t\t\tformats::SBGGR12_CSI2P,\n> -\t\t\t\tformats::SGBRG12_CSI2P,\n> -\t\t\t\tformats::SGRBG12_CSI2P,\n> -\t\t\t\tformats::SRGGB12_CSI2P\n> -\t\t\t},\n> -\t\t\tfalse,\n> -\t\t\t\"RAW12\"\n> -\t\t}\n> -\t}, {\n> -\t\tHAL_PIXEL_FORMAT_RAW16, {\n> -\t\t\t{\n> -\t\t\t\tformats::SBGGR16,\n> -\t\t\t\tformats::SGBRG16,\n> -\t\t\t\tformats::SGRBG16,\n> -\t\t\t\tformats::SRGGB16\n> -\t\t\t},\n> -\t\t\tfalse,\n> -\t\t\t\"RAW16\"\n> -\t\t}\n> -\t},\n> -};\n> -\n>  /*\n>   * \\struct Camera3StreamConfig\n>   * \\brief Data to store StreamConfiguration associated with camera3_stream(s)\n> @@ -512,242 +420,7 @@ int CameraDevice::initialize(const CameraConfigData *cameraConfigData)\n>  \t\torientation_ = 0;\n>  \t}\n>  \n> -\t/* Acquire the camera and initialize available stream configurations. */\n> -\tint ret = camera_->acquire();\n> -\tif (ret) {\n> -\t\tLOG(HAL, Error) << \"Failed to temporarily acquire the camera\";\n> -\t\treturn ret;\n> -\t}\n> -\n> -\tret = initializeStreamConfigurations();\n> -\tcamera_->release();\n> -\treturn ret;\n> -}\n> -\n> -std::vector<Size> CameraDevice::getYUVResolutions(CameraConfiguration *cameraConfig,\n> -\t\t\t\t\t\t  const PixelFormat &pixelFormat,\n> -\t\t\t\t\t\t  const std::vector<Size> &resolutions)\n> -{\n> -\tstd::vector<Size> supportedResolutions;\n> -\n> -\tStreamConfiguration &cfg = cameraConfig->at(0);\n> -\tfor (const Size &res : resolutions) {\n> -\t\tcfg.pixelFormat = pixelFormat;\n> -\t\tcfg.size = res;\n> -\n> -\t\tCameraConfiguration::Status status = cameraConfig->validate();\n> -\t\tif (status != CameraConfiguration::Valid) {\n> -\t\t\tLOG(HAL, Debug) << cfg.toString() << \" not supported\";\n> -\t\t\tcontinue;\n> -\t\t}\n> -\n> -\t\tLOG(HAL, Debug) << cfg.toString() << \" supported\";\n> -\n> -\t\tsupportedResolutions.push_back(res);\n> -\t}\n> -\n> -\treturn supportedResolutions;\n> -}\n> -\n> -std::vector<Size> CameraDevice::getRawResolutions(const libcamera::PixelFormat &pixelFormat)\n> -{\n> -\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> -\t\tcamera_->generateConfiguration({ StreamRole::Raw });\n> -\tStreamConfiguration &cfg = cameraConfig->at(0);\n> -\tconst StreamFormats &formats = cfg.formats();\n> -\tstd::vector<Size> supportedResolutions = formats.sizes(pixelFormat);\n> -\n> -\treturn supportedResolutions;\n> -}\n> -\n> -/*\n> - * Initialize the format conversion map to translate from Android format\n> - * identifier to libcamera pixel formats and fill in the list of supported\n> - * stream configurations to be reported to the Android camera framework through\n> - * the static stream configuration metadata.\n> - */\n> -int CameraDevice::initializeStreamConfigurations()\n> -{\n> -\t/*\n> -\t * Get the maximum output resolutions\n> -\t * \\todo Get this from the camera properties once defined\n> -\t */\n> -\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> -\t\tcamera_->generateConfiguration({ StillCapture });\n> -\tif (!cameraConfig) {\n> -\t\tLOG(HAL, Error) << \"Failed to get maximum resolution\";\n> -\t\treturn -EINVAL;\n> -\t}\n> -\tStreamConfiguration &cfg = cameraConfig->at(0);\n> -\n> -\t/*\n> -\t * \\todo JPEG - Adjust the maximum available resolution by taking the\n> -\t * JPEG encoder requirements into account (alignment and aspect ratio).\n> -\t */\n> -\tconst Size maxRes = cfg.size;\n> -\tLOG(HAL, Debug) << \"Maximum supported resolution: \" << maxRes.toString();\n> -\n> -\t/*\n> -\t * Build the list of supported image resolutions.\n> -\t *\n> -\t * The resolutions listed in camera3Resolution are mandatory to be\n> -\t * supported, up to the camera maximum resolution.\n> -\t *\n> -\t * Augment the list by adding resolutions calculated from the camera\n> -\t * maximum one.\n> -\t */\n> -\tstd::vector<Size> cameraResolutions;\n> -\tstd::copy_if(camera3Resolutions.begin(), camera3Resolutions.end(),\n> -\t\t     std::back_inserter(cameraResolutions),\n> -\t\t     [&](const Size &res) { return res < maxRes; });\n> -\n> -\t/*\n> -\t * The Camera3 specification suggests adding 1/2 and 1/4 of the maximum\n> -\t * resolution.\n> -\t */\n> -\tfor (unsigned int divider = 2;; divider <<= 1) {\n> -\t\tSize derivedSize{\n> -\t\t\tmaxRes.width / divider,\n> -\t\t\tmaxRes.height / divider,\n> -\t\t};\n> -\n> -\t\tif (derivedSize.width < 320 ||\n> -\t\t    derivedSize.height < 240)\n> -\t\t\tbreak;\n> -\n> -\t\tcameraResolutions.push_back(derivedSize);\n> -\t}\n> -\tcameraResolutions.push_back(maxRes);\n> -\n> -\t/* Remove duplicated entries from the list of supported resolutions. */\n> -\tstd::sort(cameraResolutions.begin(), cameraResolutions.end());\n> -\tauto last = std::unique(cameraResolutions.begin(), cameraResolutions.end());\n> -\tcameraResolutions.erase(last, cameraResolutions.end());\n> -\n> -\t/*\n> -\t * Build the list of supported camera formats.\n> -\t *\n> -\t * To each Android format a list of compatible libcamera formats is\n> -\t * associated. The first libcamera format that tests successful is added\n> -\t * to the format translation map used when configuring the streams.\n> -\t * It is then tested against the list of supported camera resolutions to\n> -\t * build the stream configuration map reported through the camera static\n> -\t * metadata.\n> -\t */\n> -\tSize maxJpegSize;\n> -\tfor (const auto &format : camera3FormatsMap) {\n> -\t\tint androidFormat = format.first;\n> -\t\tconst Camera3Format &camera3Format = format.second;\n> -\t\tconst std::vector<PixelFormat> &libcameraFormats =\n> -\t\t\tcamera3Format.libcameraFormats;\n> -\n> -\t\tLOG(HAL, Debug) << \"Trying to map Android format \"\n> -\t\t\t\t<< camera3Format.name;\n> -\n> -\t\t/*\n> -\t\t * JPEG is always supported, either produced directly by the\n> -\t\t * camera, or encoded in the HAL.\n> -\t\t */\n> -\t\tif (androidFormat == HAL_PIXEL_FORMAT_BLOB) {\n> -\t\t\tformatsMap_[androidFormat] = formats::MJPEG;\n> -\t\t\tLOG(HAL, Debug) << \"Mapped Android format \"\n> -\t\t\t\t\t<< camera3Format.name << \" to \"\n> -\t\t\t\t\t<< formats::MJPEG.toString()\n> -\t\t\t\t\t<< \" (fixed mapping)\";\n> -\t\t\tcontinue;\n> -\t\t}\n> -\n> -\t\t/*\n> -\t\t * Test the libcamera formats that can produce images\n> -\t\t * compatible with the format defined by Android.\n> -\t\t */\n> -\t\tPixelFormat mappedFormat;\n> -\t\tfor (const PixelFormat &pixelFormat : libcameraFormats) {\n> -\n> -\t\t\tLOG(HAL, Debug) << \"Testing \" << pixelFormat.toString();\n> -\n> -\t\t\t/*\n> -\t\t\t * The stream configuration size can be adjusted,\n> -\t\t\t * not the pixel format.\n> -\t\t\t *\n> -\t\t\t * \\todo This could be simplified once all pipeline\n> -\t\t\t * handlers will report the StreamFormats list of\n> -\t\t\t * supported formats.\n> -\t\t\t */\n> -\t\t\tcfg.pixelFormat = pixelFormat;\n> -\n> -\t\t\tCameraConfiguration::Status status = cameraConfig->validate();\n> -\t\t\tif (status != CameraConfiguration::Invalid &&\n> -\t\t\t    cfg.pixelFormat == pixelFormat) {\n> -\t\t\t\tmappedFormat = pixelFormat;\n> -\t\t\t\tbreak;\n> -\t\t\t}\n> -\t\t}\n> -\n> -\t\tif (!mappedFormat.isValid()) {\n> -\t\t\t/* If the format is not mandatory, skip it. */\n> -\t\t\tif (!camera3Format.mandatory)\n> -\t\t\t\tcontinue;\n> -\n> -\t\t\tLOG(HAL, Error)\n> -\t\t\t\t<< \"Failed to map mandatory Android format \"\n> -\t\t\t\t<< camera3Format.name << \" (\"\n> -\t\t\t\t<< utils::hex(androidFormat) << \"): aborting\";\n> -\t\t\treturn -EINVAL;\n> -\t\t}\n> -\n> -\t\t/*\n> -\t\t * Record the mapping and then proceed to generate the\n> -\t\t * stream configurations map, by testing the image resolutions.\n> -\t\t */\n> -\t\tformatsMap_[androidFormat] = mappedFormat;\n> -\t\tLOG(HAL, Debug) << \"Mapped Android format \"\n> -\t\t\t\t<< camera3Format.name << \" to \"\n> -\t\t\t\t<< mappedFormat.toString();\n> -\n> -\t\tstd::vector<Size> resolutions;\n> -\t\tconst PixelFormatInfo &info = PixelFormatInfo::info(mappedFormat);\n> -\t\tif (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW)\n> -\t\t\tresolutions = getRawResolutions(mappedFormat);\n> -\t\telse\n> -\t\t\tresolutions = getYUVResolutions(cameraConfig.get(),\n> -\t\t\t\t\t\t\tmappedFormat,\n> -\t\t\t\t\t\t\tcameraResolutions);\n> -\n> -\t\tfor (const Size &res : resolutions) {\n> -\t\t\tstreamConfigurations_.push_back({ res, androidFormat });\n> -\n> -\t\t\t/*\n> -\t\t\t * If the format is HAL_PIXEL_FORMAT_YCbCr_420_888\n> -\t\t\t * from which JPEG is produced, add an entry for\n> -\t\t\t * the JPEG stream.\n> -\t\t\t *\n> -\t\t\t * \\todo Wire the JPEG encoder to query the supported\n> -\t\t\t * sizes provided a list of formats it can encode.\n> -\t\t\t *\n> -\t\t\t * \\todo Support JPEG streams produced by the Camera\n> -\t\t\t * natively.\n> -\t\t\t */\n> -\t\t\tif (androidFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {\n> -\t\t\t\tstreamConfigurations_.push_back(\n> -\t\t\t\t\t{ res, HAL_PIXEL_FORMAT_BLOB });\n> -\t\t\t\tmaxJpegSize = std::max(maxJpegSize, res);\n> -\t\t\t}\n> -\t\t}\n> -\n> -\t\t/*\n> -\t\t * \\todo Calculate the maximum JPEG buffer size by asking the\n> -\t\t * encoder giving the maximum frame size required.\n> -\t\t */\n> -\t\tmaxJpegBufferSize_ = maxJpegSize.width * maxJpegSize.height * 1.5;\n> -\t}\n> -\n> -\tLOG(HAL, Debug) << \"Collected stream configuration map: \";\n> -\tfor (const auto &entry : streamConfigurations_)\n> -\t\tLOG(HAL, Debug) << \"{ \" << entry.resolution.toString() << \" - \"\n> -\t\t\t\t<< utils::hex(entry.androidFormat) << \" }\";\n> -\n> -\treturn 0;\n> +\treturn capabilities_.initialize(camera_, orientation_, facing_);\n>  }\n>  \n>  /*\n> @@ -817,802 +490,19 @@ void CameraDevice::stop()\n>  \tstate_ = State::Stopped;\n>  }\n>  \n> -void CameraDevice::setCallbacks(const camera3_callback_ops_t *callbacks)\n> +unsigned int CameraDevice::maxJpegBufferSize() const\n>  {\n> -\tcallbacks_ = callbacks;\n> +\treturn capabilities_.maxJpegBufferSize();\n>  }\n>  \n> -/*\n> - * Return static information for the camera.\n> - */\n> -const camera_metadata_t *CameraDevice::getStaticMetadata()\n> -{\n> -\tif (staticMetadata_)\n> -\t\treturn staticMetadata_->get();\n> -\n> -\tstaticMetadata_ = std::make_unique<CameraMetadata>(64, 1024);\n> -\tif (!staticMetadata_->isValid()) {\n> -\t\tLOG(HAL, Error) << \"Failed to allocate static metadata\";\n> -\t\tstaticMetadata_.reset();\n> -\t\treturn nullptr;\n> -\t}\n> -\n> -\tconst ControlInfoMap &controlsInfo = camera_->controls();\n> -\tconst ControlList &properties = camera_->properties();\n> -\n> -\t/* Color correction static metadata. */\n> -\t{\n> -\t\tstd::vector<uint8_t> data;\n> -\t\tdata.reserve(3);\n> -\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::ColorCorrectionAberrationMode);\n> -\t\tif (infoMap != controlsInfo.end()) {\n> -\t\t\tfor (const auto &value : infoMap->second.values())\n> -\t\t\t\tdata.push_back(value.get<int32_t>());\n> -\t\t} else {\n> -\t\t\tdata.push_back(ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF);\n> -\t\t}\n> -\t\tstaticMetadata_->addEntry(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,\n> -\t\t\t\t\t  data);\n> -\t}\n> -\n> -\t/* Control static metadata. */\n> -\tstd::vector<uint8_t> aeAvailableAntiBandingModes = {\n> -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF,\n> -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ,\n> -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ,\n> -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,\n> -\t\t\t\t  aeAvailableAntiBandingModes);\n> -\n> -\tstd::vector<uint8_t> aeAvailableModes = {\n> -\t\tANDROID_CONTROL_AE_MODE_ON,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_MODES,\n> -\t\t\t\t  aeAvailableModes);\n> -\n> -\tint64_t minFrameDurationNsec = -1;\n> -\tint64_t maxFrameDurationNsec = -1;\n> -\tconst auto frameDurationsInfo = controlsInfo.find(&controls::FrameDurationLimits);\n> -\tif (frameDurationsInfo != controlsInfo.end()) {\n> -\t\tminFrameDurationNsec = frameDurationsInfo->second.min().get<int64_t>() * 1000;\n> -\t\tmaxFrameDurationNsec = frameDurationsInfo->second.max().get<int64_t>() * 1000;\n> -\n> -\t\t/*\n> -\t\t * Adjust the minimum frame duration to comply with Android\n> -\t\t * requirements. The camera service mandates all preview/record\n> -\t\t * streams to have a minimum frame duration < 33,366 milliseconds\n> -\t\t * (see MAX_PREVIEW_RECORD_DURATION_NS in the camera service\n> -\t\t * implementation).\n> -\t\t *\n> -\t\t * If we're close enough (+ 500 useconds) to that value, round\n> -\t\t * the minimum frame duration of the camera to an accepted\n> -\t\t * value.\n> -\t\t */\n> -\t\tstatic constexpr int64_t MAX_PREVIEW_RECORD_DURATION_NS = 1e9 / 29.97;\n> -\t\tif (minFrameDurationNsec > MAX_PREVIEW_RECORD_DURATION_NS &&\n> -\t\t    minFrameDurationNsec < MAX_PREVIEW_RECORD_DURATION_NS + 500000)\n> -\t\t\tminFrameDurationNsec = MAX_PREVIEW_RECORD_DURATION_NS - 1000;\n> -\n> -\t\t/*\n> -\t\t * The AE routine frame rate limits are computed using the frame\n> -\t\t * duration limits, as libcamera clips the AE routine to the\n> -\t\t * frame durations.\n> -\t\t */\n> -\t\tint32_t maxFps = std::round(1e9 / minFrameDurationNsec);\n> -\t\tint32_t minFps = std::round(1e9 / maxFrameDurationNsec);\n> -\t\tminFps = std::max(1, minFps);\n> -\n> -\t\t/*\n> -\t\t * Force rounding errors so that we have the proper frame\n> -\t\t * durations for when we reuse these variables later\n> -\t\t */\n> -\t\tminFrameDurationNsec = 1e9 / maxFps;\n> -\t\tmaxFrameDurationNsec = 1e9 / minFps;\n> -\n> -\t\t/*\n> -\t\t * Register to the camera service {min, max} and {max, max}\n> -\t\t * intervals as requested by the metadata documentation.\n> -\t\t */\n> -\t\tint32_t availableAeFpsTarget[] = {\n> -\t\t\tminFps, maxFps, maxFps, maxFps\n> -\t\t};\n> -\t\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> -\t\t\t\t\t  availableAeFpsTarget);\n> -\t}\n> -\n> -\tstd::vector<int32_t> aeCompensationRange = {\n> -\t\t0, 0,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_RANGE,\n> -\t\t\t\t  aeCompensationRange);\n> -\n> -\tconst camera_metadata_rational_t aeCompensationStep[] = {\n> -\t\t{ 0, 1 }\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_STEP,\n> -\t\t\t\t  aeCompensationStep);\n> -\n> -\tstd::vector<uint8_t> availableAfModes = {\n> -\t\tANDROID_CONTROL_AF_MODE_OFF,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AF_AVAILABLE_MODES,\n> -\t\t\t\t  availableAfModes);\n> -\n> -\tstd::vector<uint8_t> availableEffects = {\n> -\t\tANDROID_CONTROL_EFFECT_MODE_OFF,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_EFFECTS,\n> -\t\t\t\t  availableEffects);\n> -\n> -\tstd::vector<uint8_t> availableSceneModes = {\n> -\t\tANDROID_CONTROL_SCENE_MODE_DISABLED,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_SCENE_MODES,\n> -\t\t\t\t  availableSceneModes);\n> -\n> -\tstd::vector<uint8_t> availableStabilizationModes = {\n> -\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,\n> -\t\t\t\t  availableStabilizationModes);\n> -\n> -\t/*\n> -\t * \\todo Inspect the Camera capabilities to report the available\n> -\t * AWB modes. Default to AUTO as CTS tests require it.\n> -\t */\n> -\tstd::vector<uint8_t> availableAwbModes = {\n> -\t\tANDROID_CONTROL_AWB_MODE_AUTO,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AWB_AVAILABLE_MODES,\n> -\t\t\t\t  availableAwbModes);\n> -\n> -\tstd::vector<int32_t> availableMaxRegions = {\n> -\t\t0, 0, 0,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_MAX_REGIONS,\n> -\t\t\t\t  availableMaxRegions);\n> -\n> -\tstd::vector<uint8_t> sceneModesOverride = {\n> -\t\tANDROID_CONTROL_AE_MODE_ON,\n> -\t\tANDROID_CONTROL_AWB_MODE_AUTO,\n> -\t\tANDROID_CONTROL_AF_MODE_OFF,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_SCENE_MODE_OVERRIDES,\n> -\t\t\t\t  sceneModesOverride);\n> -\n> -\tuint8_t aeLockAvailable = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE;\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE,\n> -\t\t\t\t  aeLockAvailable);\n> -\n> -\tuint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> -\t\t\t\t  awbLockAvailable);\n> -\n> -\tchar availableControlModes = ANDROID_CONTROL_MODE_AUTO;\n> -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_MODES,\n> -\t\t\t\t  availableControlModes);\n> -\n> -\t/* JPEG static metadata. */\n> -\n> -\t/*\n> -\t * Create the list of supported thumbnail sizes by inspecting the\n> -\t * available JPEG resolutions collected in streamConfigurations_ and\n> -\t * generate one entry for each aspect ratio.\n> -\t *\n> -\t * The JPEG thumbnailer can freely scale, so pick an arbitrary\n> -\t * (160, 160) size as the bounding rectangle, which is then cropped to\n> -\t * the different supported aspect ratios.\n> -\t */\n> -\tconstexpr Size maxJpegThumbnail(160, 160);\n> -\tstd::vector<Size> thumbnailSizes;\n> -\tthumbnailSizes.push_back({ 0, 0 });\n> -\tfor (const auto &entry : streamConfigurations_) {\n> -\t\tif (entry.androidFormat != HAL_PIXEL_FORMAT_BLOB)\n> -\t\t\tcontinue;\n> -\n> -\t\tSize thumbnailSize = maxJpegThumbnail\n> -\t\t\t\t     .boundedToAspectRatio({ entry.resolution.width,\n> -\t\t\t\t\t\t\t     entry.resolution.height });\n> -\t\tthumbnailSizes.push_back(thumbnailSize);\n> -\t}\n> -\n> -\tstd::sort(thumbnailSizes.begin(), thumbnailSizes.end());\n> -\tauto last = std::unique(thumbnailSizes.begin(), thumbnailSizes.end());\n> -\tthumbnailSizes.erase(last, thumbnailSizes.end());\n> -\n> -\t/* Transform sizes in to a list of integers that can be consumed. */\n> -\tstd::vector<int32_t> thumbnailEntries;\n> -\tthumbnailEntries.reserve(thumbnailSizes.size() * 2);\n> -\tfor (const auto &size : thumbnailSizes) {\n> -\t\tthumbnailEntries.push_back(size.width);\n> -\t\tthumbnailEntries.push_back(size.height);\n> -\t}\n> -\tstaticMetadata_->addEntry(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,\n> -\t\t\t\t  thumbnailEntries);\n> -\n> -\tstaticMetadata_->addEntry(ANDROID_JPEG_MAX_SIZE, maxJpegBufferSize_);\n> -\n> -\t/* Sensor static metadata. */\n> -\tstd::array<int32_t, 2> pixelArraySize;\n> -\t{\n> -\t\tconst Size &size = properties.get(properties::PixelArraySize);\n> -\t\tpixelArraySize[0] = size.width;\n> -\t\tpixelArraySize[1] = size.height;\n> -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,\n> -\t\t\t\t\t  pixelArraySize);\n> -\t}\n> -\n> -\tif (properties.contains(properties::UnitCellSize)) {\n> -\t\tconst Size &cellSize = properties.get<Size>(properties::UnitCellSize);\n> -\t\tstd::array<float, 2> physicalSize{\n> -\t\t\tcellSize.width * pixelArraySize[0] / 1e6f,\n> -\t\t\tcellSize.height * pixelArraySize[1] / 1e6f\n> -\t\t};\n> -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,\n> -\t\t\t\t\t  physicalSize);\n> -\t}\n> -\n> -\t{\n> -\t\tconst Span<const Rectangle> &rects =\n> -\t\t\tproperties.get(properties::PixelArrayActiveAreas);\n> -\t\tstd::vector<int32_t> data{\n> -\t\t\tstatic_cast<int32_t>(rects[0].x),\n> -\t\t\tstatic_cast<int32_t>(rects[0].y),\n> -\t\t\tstatic_cast<int32_t>(rects[0].width),\n> -\t\t\tstatic_cast<int32_t>(rects[0].height),\n> -\t\t};\n> -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,\n> -\t\t\t\t\t  data);\n> -\t}\n> -\n> -\tint32_t sensitivityRange[] = {\n> -\t\t32, 2400,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,\n> -\t\t\t\t  sensitivityRange);\n> -\n> -\t/* Report the color filter arrangement if the camera reports it. */\n> -\tif (properties.contains(properties::draft::ColorFilterArrangement)) {\n> -\t\tuint8_t filterArr = properties.get(properties::draft::ColorFilterArrangement);\n> -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,\n> -\t\t\t\t\t  filterArr);\n> -\t}\n> -\n> -\tconst auto &exposureInfo = controlsInfo.find(&controls::ExposureTime);\n> -\tif (exposureInfo != controlsInfo.end()) {\n> -\t\tint64_t exposureTimeRange[2] = {\n> -\t\t\texposureInfo->second.min().get<int32_t>() * 1000LL,\n> -\t\t\texposureInfo->second.max().get<int32_t>() * 1000LL,\n> -\t\t};\n> -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,\n> -\t\t\t\t\t  exposureTimeRange, 2);\n> -\t}\n> -\n> -\tstaticMetadata_->addEntry(ANDROID_SENSOR_ORIENTATION, orientation_);\n> -\n> -\tstd::vector<int32_t> testPatternModes = {\n> -\t\tANDROID_SENSOR_TEST_PATTERN_MODE_OFF\n> -\t};\n> -\tconst auto &testPatternsInfo =\n> -\t\tcontrolsInfo.find(&controls::draft::TestPatternMode);\n> -\tif (testPatternsInfo != controlsInfo.end()) {\n> -\t\tconst auto &values = testPatternsInfo->second.values();\n> -\t\tASSERT(!values.empty());\n> -\t\tfor (const auto &value : values) {\n> -\t\t\tswitch (value.get<int32_t>()) {\n> -\t\t\tcase controls::draft::TestPatternModeOff:\n> -\t\t\t\t/*\n> -\t\t\t\t * ANDROID_SENSOR_TEST_PATTERN_MODE_OFF is\n> -\t\t\t\t * already in testPatternModes.\n> -\t\t\t\t */\n> -\t\t\t\tbreak;\n> -\n> -\t\t\tcase controls::draft::TestPatternModeSolidColor:\n> -\t\t\t\ttestPatternModes.push_back(\n> -\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR);\n> -\t\t\t\tbreak;\n> -\n> -\t\t\tcase controls::draft::TestPatternModeColorBars:\n> -\t\t\t\ttestPatternModes.push_back(\n> -\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS);\n> -\t\t\t\tbreak;\n> -\n> -\t\t\tcase controls::draft::TestPatternModeColorBarsFadeToGray:\n> -\t\t\t\ttestPatternModes.push_back(\n> -\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY);\n> -\t\t\t\tbreak;\n> -\n> -\t\t\tcase controls::draft::TestPatternModePn9:\n> -\t\t\t\ttestPatternModes.push_back(\n> -\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_PN9);\n> -\t\t\t\tbreak;\n> -\n> -\t\t\tcase controls::draft::TestPatternModeCustom1:\n> -\t\t\t\t/* We don't support this yet. */\n> -\t\t\t\tbreak;\n> -\n> -\t\t\tdefault:\n> -\t\t\t\tLOG(HAL, Error) << \"Unknown test pattern mode: \"\n> -\t\t\t\t\t\t<< value.get<int32_t>();\n> -\t\t\t\tcontinue;\n> -\t\t\t}\n> -\t\t}\n> -\t}\n> -\tstaticMetadata_->addEntry(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,\n> -\t\t\t\t  testPatternModes);\n> -\n> -\tuint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;\n> -\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,\n> -\t\t\t\t  timestampSource);\n> -\n> -\tif (maxFrameDurationNsec > 0)\n> -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,\n> -\t\t\t\t\t  maxFrameDurationNsec);\n> -\n> -\t/* Statistics static metadata. */\n> -\tuint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;\n> -\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,\n> -\t\t\t\t  faceDetectMode);\n> -\n> -\tint32_t maxFaceCount = 0;\n> -\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,\n> -\t\t\t\t  maxFaceCount);\n> -\n> -\t{\n> -\t\tstd::vector<uint8_t> data;\n> -\t\tdata.reserve(2);\n> -\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::LensShadingMapMode);\n> -\t\tif (infoMap != controlsInfo.end()) {\n> -\t\t\tfor (const auto &value : infoMap->second.values())\n> -\t\t\t\tdata.push_back(value.get<int32_t>());\n> -\t\t} else {\n> -\t\t\tdata.push_back(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF);\n> -\t\t}\n> -\t\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,\n> -\t\t\t\t\t  data);\n> -\t}\n> -\n> -\t/* Sync static metadata. */\n> -\tint32_t maxLatency = ANDROID_SYNC_MAX_LATENCY_UNKNOWN;\n> -\tstaticMetadata_->addEntry(ANDROID_SYNC_MAX_LATENCY, maxLatency);\n> -\n> -\t/* Flash static metadata. */\n> -\tchar flashAvailable = ANDROID_FLASH_INFO_AVAILABLE_FALSE;\n> -\tstaticMetadata_->addEntry(ANDROID_FLASH_INFO_AVAILABLE,\n> -\t\t\t\t  flashAvailable);\n> -\n> -\t/* Lens static metadata. */\n> -\tstd::vector<float> lensApertures = {\n> -\t\t2.53 / 100,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_APERTURES,\n> -\t\t\t\t  lensApertures);\n> -\n> -\tuint8_t lensFacing;\n> -\tswitch (facing_) {\n> -\tdefault:\n> -\tcase CAMERA_FACING_FRONT:\n> -\t\tlensFacing = ANDROID_LENS_FACING_FRONT;\n> -\t\tbreak;\n> -\tcase CAMERA_FACING_BACK:\n> -\t\tlensFacing = ANDROID_LENS_FACING_BACK;\n> -\t\tbreak;\n> -\tcase CAMERA_FACING_EXTERNAL:\n> -\t\tlensFacing = ANDROID_LENS_FACING_EXTERNAL;\n> -\t\tbreak;\n> -\t}\n> -\tstaticMetadata_->addEntry(ANDROID_LENS_FACING, lensFacing);\n> -\n> -\tstd::vector<float> lensFocalLengths = {\n> -\t\t1,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,\n> -\t\t\t\t  lensFocalLengths);\n> -\n> -\tstd::vector<uint8_t> opticalStabilizations = {\n> -\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,\n> -\t\t\t\t  opticalStabilizations);\n> -\n> -\tfloat hypeFocalDistance = 0;\n> -\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,\n> -\t\t\t\t  hypeFocalDistance);\n> -\n> -\tfloat minFocusDistance = 0;\n> -\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,\n> -\t\t\t\t  minFocusDistance);\n> -\n> -\t/* Noise reduction modes. */\n> -\t{\n> -\t\tstd::vector<uint8_t> data;\n> -\t\tdata.reserve(5);\n> -\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::NoiseReductionMode);\n> -\t\tif (infoMap != controlsInfo.end()) {\n> -\t\t\tfor (const auto &value : infoMap->second.values())\n> -\t\t\t\tdata.push_back(value.get<int32_t>());\n> -\t\t} else {\n> -\t\t\tdata.push_back(ANDROID_NOISE_REDUCTION_MODE_OFF);\n> -\t\t}\n> -\t\tstaticMetadata_->addEntry(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,\n> -\t\t\t\t\t  data);\n> -\t}\n> -\n> -\t/* Scaler static metadata. */\n> -\n> -\t/*\n> -\t * \\todo The digital zoom factor is a property that depends on the\n> -\t * desired output configuration and the sensor frame size input to the\n> -\t * ISP. This information is not available to the Android HAL, not at\n> -\t * initialization time at least.\n> -\t *\n> -\t * As a workaround rely on pipeline handlers initializing the\n> -\t * ScalerCrop control with the camera default configuration and use the\n> -\t * maximum and minimum crop rectangles to calculate the digital zoom\n> -\t * factor.\n> -\t */\n> -\tfloat maxZoom = 1.0f;\n> -\tconst auto scalerCrop = controlsInfo.find(&controls::ScalerCrop);\n> -\tif (scalerCrop != controlsInfo.end()) {\n> -\t\tRectangle min = scalerCrop->second.min().get<Rectangle>();\n> -\t\tRectangle max = scalerCrop->second.max().get<Rectangle>();\n> -\t\tmaxZoom = std::min(1.0f * max.width / min.width,\n> -\t\t\t\t   1.0f * max.height / min.height);\n> -\t}\n> -\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,\n> -\t\t\t\t  maxZoom);\n> -\n> -\tstd::vector<uint32_t> availableStreamConfigurations;\n> -\tavailableStreamConfigurations.reserve(streamConfigurations_.size() * 4);\n> -\tfor (const auto &entry : streamConfigurations_) {\n> -\t\tavailableStreamConfigurations.push_back(entry.androidFormat);\n> -\t\tavailableStreamConfigurations.push_back(entry.resolution.width);\n> -\t\tavailableStreamConfigurations.push_back(entry.resolution.height);\n> -\t\tavailableStreamConfigurations.push_back(\n> -\t\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);\n> -\t}\n> -\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,\n> -\t\t\t\t  availableStreamConfigurations);\n> -\n> -\tstd::vector<int64_t> availableStallDurations = {\n> -\t\tANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920, 33333333,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,\n> -\t\t\t\t  availableStallDurations);\n> -\n> -\t/* Use the minimum frame duration for all the YUV/RGB formats. */\n> -\tif (minFrameDurationNsec > 0) {\n> -\t\tstd::vector<int64_t> minFrameDurations;\n> -\t\tminFrameDurations.reserve(streamConfigurations_.size() * 4);\n> -\t\tfor (const auto &entry : streamConfigurations_) {\n> -\t\t\tminFrameDurations.push_back(entry.androidFormat);\n> -\t\t\tminFrameDurations.push_back(entry.resolution.width);\n> -\t\t\tminFrameDurations.push_back(entry.resolution.height);\n> -\t\t\tminFrameDurations.push_back(minFrameDurationNsec);\n> -\t\t}\n> -\t\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,\n> -\t\t\t\t\t  minFrameDurations);\n> -\t}\n> -\n> -\tuint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY;\n> -\tstaticMetadata_->addEntry(ANDROID_SCALER_CROPPING_TYPE, croppingType);\n> -\n> -\t/* Info static metadata. */\n> -\tuint8_t supportedHWLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;\n> -\tstaticMetadata_->addEntry(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,\n> -\t\t\t\t  supportedHWLevel);\n> -\n> -\t/* Request static metadata. */\n> -\tint32_t partialResultCount = 1;\n> -\tstaticMetadata_->addEntry(ANDROID_REQUEST_PARTIAL_RESULT_COUNT,\n> -\t\t\t\t  partialResultCount);\n> -\n> -\t{\n> -\t\t/* Default the value to 2 if not reported by the camera. */\n> -\t\tuint8_t maxPipelineDepth = 2;\n> -\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::PipelineDepth);\n> -\t\tif (infoMap != controlsInfo.end())\n> -\t\t\tmaxPipelineDepth = infoMap->second.max().get<int32_t>();\n> -\t\tstaticMetadata_->addEntry(ANDROID_REQUEST_PIPELINE_MAX_DEPTH,\n> -\t\t\t\t\t  maxPipelineDepth);\n> -\t}\n> -\n> -\t/* LIMITED does not support reprocessing. */\n> -\tuint32_t maxNumInputStreams = 0;\n> -\tstaticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,\n> -\t\t\t\t  maxNumInputStreams);\n> -\n> -\tstd::vector<uint8_t> availableCapabilities = {\n> -\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,\n> -\t};\n> -\n> -\t/* Report if camera supports RAW. */\n> -\tbool rawStreamAvailable = false;\n> -\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> -\t\tcamera_->generateConfiguration({ StreamRole::Raw });\n> -\tif (cameraConfig && !cameraConfig->empty()) {\n> -\t\tconst PixelFormatInfo &info =\n> -\t\t\tPixelFormatInfo::info(cameraConfig->at(0).pixelFormat);\n> -\t\t/* Only advertise RAW support if RAW16 is possible. */\n> -\t\tif (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW &&\n> -\t\t    info.bitsPerPixel == 16) {\n> -\t\t\trawStreamAvailable = true;\n> -\t\t\tavailableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);\n> -\t\t}\n> -\t}\n> -\n> -\t/* Number of { RAW, YUV, JPEG } supported output streams */\n> -\tint32_t numOutStreams[] = { rawStreamAvailable, 2, 1 };\n> -\tstaticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,\n> -\t\t\t\t  numOutStreams);\n> -\n> -\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CAPABILITIES,\n> -\t\t\t\t  availableCapabilities);\n> -\n> -\tstd::vector<int32_t> availableCharacteristicsKeys = {\n> -\t\tANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,\n> -\t\tANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,\n> -\t\tANDROID_CONTROL_AE_AVAILABLE_MODES,\n> -\t\tANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> -\t\tANDROID_CONTROL_AE_COMPENSATION_RANGE,\n> -\t\tANDROID_CONTROL_AE_COMPENSATION_STEP,\n> -\t\tANDROID_CONTROL_AE_LOCK_AVAILABLE,\n> -\t\tANDROID_CONTROL_AF_AVAILABLE_MODES,\n> -\t\tANDROID_CONTROL_AVAILABLE_EFFECTS,\n> -\t\tANDROID_CONTROL_AVAILABLE_MODES,\n> -\t\tANDROID_CONTROL_AVAILABLE_SCENE_MODES,\n> -\t\tANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,\n> -\t\tANDROID_CONTROL_AWB_AVAILABLE_MODES,\n> -\t\tANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> -\t\tANDROID_CONTROL_MAX_REGIONS,\n> -\t\tANDROID_CONTROL_SCENE_MODE_OVERRIDES,\n> -\t\tANDROID_FLASH_INFO_AVAILABLE,\n> -\t\tANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,\n> -\t\tANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,\n> -\t\tANDROID_JPEG_MAX_SIZE,\n> -\t\tANDROID_LENS_FACING,\n> -\t\tANDROID_LENS_INFO_AVAILABLE_APERTURES,\n> -\t\tANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,\n> -\t\tANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,\n> -\t\tANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,\n> -\t\tANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,\n> -\t\tANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,\n> -\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES,\n> -\t\tANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,\n> -\t\tANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,\n> -\t\tANDROID_REQUEST_PARTIAL_RESULT_COUNT,\n> -\t\tANDROID_REQUEST_PIPELINE_MAX_DEPTH,\n> -\t\tANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,\n> -\t\tANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,\n> -\t\tANDROID_SCALER_AVAILABLE_STALL_DURATIONS,\n> -\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,\n> -\t\tANDROID_SCALER_CROPPING_TYPE,\n> -\t\tANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,\n> -\t\tANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,\n> -\t\tANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,\n> -\t\tANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,\n> -\t\tANDROID_SENSOR_INFO_MAX_FRAME_DURATION,\n> -\t\tANDROID_SENSOR_INFO_PHYSICAL_SIZE,\n> -\t\tANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,\n> -\t\tANDROID_SENSOR_INFO_SENSITIVITY_RANGE,\n> -\t\tANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,\n> -\t\tANDROID_SENSOR_ORIENTATION,\n> -\t\tANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,\n> -\t\tANDROID_STATISTICS_INFO_MAX_FACE_COUNT,\n> -\t\tANDROID_SYNC_MAX_LATENCY,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,\n> -\t\t\t\t  availableCharacteristicsKeys);\n> -\n> -\tstd::vector<int32_t> availableRequestKeys = {\n> -\t\tANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> -\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> -\t\tANDROID_CONTROL_AE_LOCK,\n> -\t\tANDROID_CONTROL_AE_MODE,\n> -\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> -\t\tANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> -\t\tANDROID_CONTROL_AF_MODE,\n> -\t\tANDROID_CONTROL_AF_TRIGGER,\n> -\t\tANDROID_CONTROL_AWB_LOCK,\n> -\t\tANDROID_CONTROL_AWB_MODE,\n> -\t\tANDROID_CONTROL_CAPTURE_INTENT,\n> -\t\tANDROID_CONTROL_EFFECT_MODE,\n> -\t\tANDROID_CONTROL_MODE,\n> -\t\tANDROID_CONTROL_SCENE_MODE,\n> -\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE,\n> -\t\tANDROID_FLASH_MODE,\n> -\t\tANDROID_JPEG_ORIENTATION,\n> -\t\tANDROID_JPEG_QUALITY,\n> -\t\tANDROID_JPEG_THUMBNAIL_QUALITY,\n> -\t\tANDROID_JPEG_THUMBNAIL_SIZE,\n> -\t\tANDROID_LENS_APERTURE,\n> -\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> -\t\tANDROID_NOISE_REDUCTION_MODE,\n> -\t\tANDROID_SCALER_CROP_REGION,\n> -\t\tANDROID_STATISTICS_FACE_DETECT_MODE\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,\n> -\t\t\t\t  availableRequestKeys);\n> -\n> -\tstd::vector<int32_t> availableResultKeys = {\n> -\t\tANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> -\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> -\t\tANDROID_CONTROL_AE_LOCK,\n> -\t\tANDROID_CONTROL_AE_MODE,\n> -\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> -\t\tANDROID_CONTROL_AE_STATE,\n> -\t\tANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> -\t\tANDROID_CONTROL_AF_MODE,\n> -\t\tANDROID_CONTROL_AF_STATE,\n> -\t\tANDROID_CONTROL_AF_TRIGGER,\n> -\t\tANDROID_CONTROL_AWB_LOCK,\n> -\t\tANDROID_CONTROL_AWB_MODE,\n> -\t\tANDROID_CONTROL_AWB_STATE,\n> -\t\tANDROID_CONTROL_CAPTURE_INTENT,\n> -\t\tANDROID_CONTROL_EFFECT_MODE,\n> -\t\tANDROID_CONTROL_MODE,\n> -\t\tANDROID_CONTROL_SCENE_MODE,\n> -\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE,\n> -\t\tANDROID_FLASH_MODE,\n> -\t\tANDROID_FLASH_STATE,\n> -\t\tANDROID_JPEG_GPS_COORDINATES,\n> -\t\tANDROID_JPEG_GPS_PROCESSING_METHOD,\n> -\t\tANDROID_JPEG_GPS_TIMESTAMP,\n> -\t\tANDROID_JPEG_ORIENTATION,\n> -\t\tANDROID_JPEG_QUALITY,\n> -\t\tANDROID_JPEG_SIZE,\n> -\t\tANDROID_JPEG_THUMBNAIL_QUALITY,\n> -\t\tANDROID_JPEG_THUMBNAIL_SIZE,\n> -\t\tANDROID_LENS_APERTURE,\n> -\t\tANDROID_LENS_FOCAL_LENGTH,\n> -\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> -\t\tANDROID_LENS_STATE,\n> -\t\tANDROID_NOISE_REDUCTION_MODE,\n> -\t\tANDROID_REQUEST_PIPELINE_DEPTH,\n> -\t\tANDROID_SCALER_CROP_REGION,\n> -\t\tANDROID_SENSOR_EXPOSURE_TIME,\n> -\t\tANDROID_SENSOR_FRAME_DURATION,\n> -\t\tANDROID_SENSOR_ROLLING_SHUTTER_SKEW,\n> -\t\tANDROID_SENSOR_TEST_PATTERN_MODE,\n> -\t\tANDROID_SENSOR_TIMESTAMP,\n> -\t\tANDROID_STATISTICS_FACE_DETECT_MODE,\n> -\t\tANDROID_STATISTICS_LENS_SHADING_MAP_MODE,\n> -\t\tANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,\n> -\t\tANDROID_STATISTICS_SCENE_FLICKER,\n> -\t};\n> -\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,\n> -\t\t\t\t  availableResultKeys);\n> -\n> -\tif (!staticMetadata_->isValid()) {\n> -\t\tLOG(HAL, Error) << \"Failed to construct static metadata\";\n> -\t\tstaticMetadata_.reset();\n> -\t\treturn nullptr;\n> -\t}\n> -\n> -\tif (staticMetadata_->resized()) {\n> -\t\tauto [entryCount, dataCount] = staticMetadata_->usage();\n> -\t\tLOG(HAL, Info)\n> -\t\t\t<< \"Static metadata resized: \" << entryCount\n> -\t\t\t<< \" entries and \" << dataCount << \" bytes used\";\n> -\t}\n> -\n> -\treturn staticMetadata_->get();\n> -}\n> -\n> -std::unique_ptr<CameraMetadata> CameraDevice::requestTemplatePreview()\n> +void CameraDevice::setCallbacks(const camera3_callback_ops_t *callbacks)\n>  {\n> -\t/*\n> -\t * \\todo Keep this in sync with the actual number of entries.\n> -\t * Currently: 20 entries, 35 bytes\n> -\t */\n> -\tauto requestTemplate = std::make_unique<CameraMetadata>(21, 36);\n> -\tif (!requestTemplate->isValid()) {\n> -\t\treturn nullptr;\n> -\t}\n> -\n> -\t/* Get the FPS range registered in the static metadata. */\n> -\tcamera_metadata_ro_entry_t entry;\n> -\tbool found = staticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> -\t\t\t\t\t       &entry);\n> -\tif (!found) {\n> -\t\tLOG(HAL, Error) << \"Cannot create capture template without FPS range\";\n> -\t\treturn nullptr;\n> -\t}\n> -\n> -\t/*\n> -\t * Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata\n> -\t * has been assembled as {{min, max} {max, max}}.\n> -\t */\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> -\t\t\t\t  entry.data.i32, 2);\n> -\n> -\tuint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_MODE, aeMode);\n> -\n> -\tint32_t aeExposureCompensation = 0;\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> -\t\t\t\t  aeExposureCompensation);\n> -\n> -\tuint8_t aePrecaptureTrigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> -\t\t\t\t  aePrecaptureTrigger);\n> -\n> -\tuint8_t aeLock = ANDROID_CONTROL_AE_LOCK_OFF;\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_LOCK, aeLock);\n> -\n> -\tuint8_t aeAntibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> -\t\t\t\t  aeAntibandingMode);\n> -\n> -\tuint8_t afMode = ANDROID_CONTROL_AF_MODE_OFF;\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_AF_MODE, afMode);\n> -\n> -\tuint8_t afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_AF_TRIGGER, afTrigger);\n> -\n> -\tuint8_t awbMode = ANDROID_CONTROL_AWB_MODE_AUTO;\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_AWB_MODE, awbMode);\n> -\n> -\tuint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_AWB_LOCK, awbLock);\n> -\n> -\tuint8_t flashMode = ANDROID_FLASH_MODE_OFF;\n> -\trequestTemplate->addEntry(ANDROID_FLASH_MODE, flashMode);\n> -\n> -\tuint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;\n> -\trequestTemplate->addEntry(ANDROID_STATISTICS_FACE_DETECT_MODE,\n> -\t\t\t\t  faceDetectMode);\n> -\n> -\tuint8_t noiseReduction = ANDROID_NOISE_REDUCTION_MODE_OFF;\n> -\trequestTemplate->addEntry(ANDROID_NOISE_REDUCTION_MODE,\n> -\t\t\t\t  noiseReduction);\n> -\n> -\tuint8_t aberrationMode = ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF;\n> -\trequestTemplate->addEntry(ANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> -\t\t\t\t  aberrationMode);\n> -\n> -\tuint8_t controlMode = ANDROID_CONTROL_MODE_AUTO;\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_MODE, controlMode);\n> -\n> -\tfloat lensAperture = 2.53 / 100;\n> -\trequestTemplate->addEntry(ANDROID_LENS_APERTURE, lensAperture);\n> -\n> -\tuint8_t opticalStabilization = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;\n> -\trequestTemplate->addEntry(ANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> -\t\t\t\t  opticalStabilization);\n> -\n> -\tuint8_t captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;\n> -\trequestTemplate->addEntry(ANDROID_CONTROL_CAPTURE_INTENT,\n> -\t\t\t\t  captureIntent);\n> -\n> -\treturn requestTemplate;\n> +\tcallbacks_ = callbacks;\n>  }\n>  \n> -std::unique_ptr<CameraMetadata> CameraDevice::requestTemplateVideo()\n> +const camera_metadata_t *CameraDevice::getStaticMetadata()\n>  {\n> -\tstd::unique_ptr<CameraMetadata> previewTemplate = requestTemplatePreview();\n> -\tif (!previewTemplate)\n> -\t\treturn nullptr;\n> -\n> -\t/*\n> -\t * The video template requires a fixed FPS range. Everything else\n> -\t * stays the same as the preview template.\n> -\t */\n> -\tcamera_metadata_ro_entry_t entry;\n> -\tstaticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> -\t\t\t\t  &entry);\n> -\n> -\t/*\n> -\t * Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata\n> -\t * has been assembled as {{min, max} {max, max}}.\n> -\t */\n> -\tpreviewTemplate->updateEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> -\t\t\t\t     entry.data.i32 + 2, 2);\n> -\n> -\treturn previewTemplate;\n> +\treturn capabilities_.staticMetadata()->get();\n>  }\n>  \n>  /*\n> @@ -1630,7 +520,7 @@ const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type)\n>  \tswitch (type) {\n>  \tcase CAMERA3_TEMPLATE_PREVIEW:\n>  \t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;\n> -\t\trequestTemplate = requestTemplatePreview();\n> +\t\trequestTemplate = capabilities_.requestTemplatePreview();\n>  \t\tbreak;\n>  \tcase CAMERA3_TEMPLATE_STILL_CAPTURE:\n>  \t\t/*\n> @@ -1638,15 +528,15 @@ const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type)\n>  \t\t * for the torch mode we currently do not support.\n>  \t\t */\n>  \t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;\n> -\t\trequestTemplate = requestTemplatePreview();\n> +\t\trequestTemplate = capabilities_.requestTemplatePreview();\n>  \t\tbreak;\n>  \tcase CAMERA3_TEMPLATE_VIDEO_RECORD:\n>  \t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;\n> -\t\trequestTemplate = requestTemplateVideo();\n> +\t\trequestTemplate = capabilities_.requestTemplateVideo();\n>  \t\tbreak;\n>  \tcase CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:\n>  \t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;\n> -\t\trequestTemplate = requestTemplateVideo();\n> +\t\trequestTemplate = capabilities_.requestTemplateVideo();\n>  \t\tbreak;\n>  \t/* \\todo Implement templates generation for the remaining use cases. */\n>  \tcase CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:\n> @@ -1668,19 +558,6 @@ const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type)\n>  \treturn requestTemplates_[type]->get();\n>  }\n>  \n> -PixelFormat CameraDevice::toPixelFormat(int format) const\n> -{\n> -\t/* Translate Android format code to libcamera pixel format. */\n> -\tauto it = formatsMap_.find(format);\n> -\tif (it == formatsMap_.end()) {\n> -\t\tLOG(HAL, Error) << \"Requested format \" << utils::hex(format)\n> -\t\t\t\t<< \" not supported\";\n> -\t\treturn PixelFormat();\n> -\t}\n> -\n> -\treturn it->second;\n> -}\n> -\n>  /*\n>   * Inspect the stream_list to produce a list of StreamConfiguration to\n>   * be use to configure the Camera.\n> @@ -1727,7 +604,7 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)\n>  \t\tcamera3_stream_t *stream = stream_list->streams[i];\n>  \t\tSize size(stream->width, stream->height);\n>  \n> -\t\tPixelFormat format = toPixelFormat(stream->format);\n> +\t\tPixelFormat format = capabilities_.toPixelFormat(stream->format);\n>  \n>  \t\tLOG(HAL, Info) << \"Stream #\" << i\n>  \t\t\t       << \", direction: \" << stream->stream_type\n> diff --git a/src/android/camera_device.h b/src/android/camera_device.h\n> index 4aadb27c562c..090fe28a551e 100644\n> --- a/src/android/camera_device.h\n> +++ b/src/android/camera_device.h\n> @@ -10,14 +10,12 @@\n>  #include <map>\n>  #include <memory>\n>  #include <mutex>\n> -#include <tuple>\n>  #include <vector>\n>  \n>  #include <hardware/camera3.h>\n>  \n>  #include <libcamera/buffer.h>\n>  #include <libcamera/camera.h>\n> -#include <libcamera/geometry.h>\n>  #include <libcamera/request.h>\n>  #include <libcamera/stream.h>\n>  \n> @@ -26,6 +24,7 @@\n>  #include \"libcamera/internal/message.h\"\n>  #include \"libcamera/internal/thread.h\"\n>  \n> +#include \"camera_capabilities.h\"\n>  #include \"camera_metadata.h\"\n>  #include \"camera_stream.h\"\n>  #include \"camera_worker.h\"\n> @@ -57,7 +56,7 @@ public:\n>  \tconst std::string &model() const { return model_; }\n>  \tint facing() const { return facing_; }\n>  \tint orientation() const { return orientation_; }\n> -\tunsigned int maxJpegBufferSize() const { return maxJpegBufferSize_; }\n> +\tunsigned int maxJpegBufferSize() const;\n>  \n>  \tvoid setCallbacks(const camera3_callback_ops_t *callbacks);\n>  \tconst camera_metadata_t *getStaticMetadata();\n> @@ -86,11 +85,6 @@ private:\n>  \t\tstd::unique_ptr<CaptureRequest> request_;\n>  \t};\n>  \n> -\tstruct Camera3StreamConfiguration {\n> -\t\tlibcamera::Size resolution;\n> -\t\tint androidFormat;\n> -\t};\n> -\n>  \tenum class State {\n>  \t\tStopped,\n>  \t\tFlushing,\n> @@ -99,22 +93,11 @@ private:\n>  \n>  \tvoid stop();\n>  \n> -\tint initializeStreamConfigurations();\n> -\tstd::vector<libcamera::Size>\n> -\tgetYUVResolutions(libcamera::CameraConfiguration *cameraConfig,\n> -\t\t\t  const libcamera::PixelFormat &pixelFormat,\n> -\t\t\t  const std::vector<libcamera::Size> &resolutions);\n> -\tstd::vector<libcamera::Size>\n> -\tgetRawResolutions(const libcamera::PixelFormat &pixelFormat);\n> -\n>  \tlibcamera::FrameBuffer *createFrameBuffer(const buffer_handle_t camera3buffer);\n>  \tvoid abortRequest(camera3_capture_request_t *request);\n>  \tvoid notifyShutter(uint32_t frameNumber, uint64_t timestamp);\n>  \tvoid notifyError(uint32_t frameNumber, camera3_stream_t *stream,\n>  \t\t\t camera3_error_msg_code code);\n> -\tstd::unique_ptr<CameraMetadata> requestTemplatePreview();\n> -\tstd::unique_ptr<CameraMetadata> requestTemplateVideo();\n> -\tlibcamera::PixelFormat toPixelFormat(int format) const;\n>  \tint processControls(Camera3RequestDescriptor *descriptor);\n>  \tstd::unique_ptr<CameraMetadata> getResultMetadata(\n>  \t\tconst Camera3RequestDescriptor &descriptor) const;\n> @@ -129,13 +112,11 @@ private:\n>  \n>  \tstd::shared_ptr<libcamera::Camera> camera_;\n>  \tstd::unique_ptr<libcamera::CameraConfiguration> config_;\n> +\tCameraCapabilities capabilities_;\n>  \n> -\tstd::unique_ptr<CameraMetadata> staticMetadata_;\n>  \tstd::map<unsigned int, std::unique_ptr<CameraMetadata>> requestTemplates_;\n>  \tconst camera3_callback_ops_t *callbacks_;\n>  \n> -\tstd::vector<Camera3StreamConfiguration> streamConfigurations_;\n> -\tstd::map<int, libcamera::PixelFormat> formatsMap_;\n>  \tstd::vector<CameraStream> streams_;\n>  \n>  \tlibcamera::Mutex descriptorsMutex_; /* Protects descriptors_. */\n> @@ -147,8 +128,6 @@ private:\n>  \tint facing_;\n>  \tint orientation_;\n>  \n> -\tunsigned int maxJpegBufferSize_;\n> -\n>  \tCameraMetadata lastSettings_;\n>  };\n>  \n> diff --git a/src/android/meson.build b/src/android/meson.build\n> index 3893e5b5b832..e093aa2ec565 100644\n> --- a/src/android/meson.build\n> +++ b/src/android/meson.build\n> @@ -45,6 +45,7 @@ subdir('cros')\n>  android_hal_sources = files([\n>      'camera3_hal.cpp',\n>      'camera_hal_manager.cpp',\n> +    'camera_capabilities.cpp',\n>      'camera_device.cpp',\n>      'camera_hal_config.cpp',\n>      'camera_metadata.cpp',\n> -- \n> 2.31.1\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id A4790BE58C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 21 Jun 2021 10:54:55 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 2682668939;\n\tMon, 21 Jun 2021 12:54:55 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 5B0CA60295\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 21 Jun 2021 12:54:54 +0200 (CEST)","from pyrite.rasen.tech (unknown\n\t[IPv6:2400:4051:61:600:2c71:1b79:d06d:5032])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id DC20C268;\n\tMon, 21 Jun 2021 12:54:51 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"vZ71xmcz\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1624272894;\n\tbh=PHcpYvcHF5fBvF/7qfebu0mrsp4R5oX6GhkrnSsnjdY=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=vZ71xmczrMBImTRecnIyzDSKOy9XSkj9vjAA1ofp5JubT05LOd01V6E30hnErBGbu\n\tfd1Q6hneWjhE35LsWwBH88DSQz76V3mriHgrUYXDSQ+WSe43MdSbmoYaTDNHjhtZ9R\n\tWu+8zkJ6UPUx5rURrz/NWfVGL7ELxhn2yxhGCW8w=","Date":"Mon, 21 Jun 2021 19:54:45 +0900","From":"paul.elder@ideasonboard.com","To":"Jacopo Mondi <jacopo@jmondi.org>","Message-ID":"<20210621105445.GA1899306@pyrite.rasen.tech>","References":"<20210619105151.20012-1-jacopo@jmondi.org>\n\t<20210619105151.20012-2-jacopo@jmondi.org>","MIME-Version":"1.0","Content-Type":"text/plain; charset=us-ascii","Content-Disposition":"inline","In-Reply-To":"<20210619105151.20012-2-jacopo@jmondi.org>","Subject":"Re: [libcamera-devel] [RFC 1/1] android: Introduce\n\tCameraCapabilties class","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":17661,"web_url":"https://patchwork.libcamera.org/comment/17661/","msgid":"<20210621135345.a3gug5ei6zxqjnif@uno.localdomain>","date":"2021-06-21T13:53:45","subject":"Re: [libcamera-devel] [RFC 1/1] android: Introduce\n\tCameraCapabilties class","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Laurent,\n\nOn Sun, Jun 20, 2021 at 04:12:11AM +0300, Laurent Pinchart wrote:\n> Hi Jacopo,\n>\n> Thank you for the patch.\n>\n> On Sat, Jun 19, 2021 at 12:51:51PM +0200, Jacopo Mondi wrote:\n> > The camera_device.cpp has grown a little too much, and it has quickly\n> > become hard to maintain. Break out the handling of the static\n> > information collected at camera initialization time to a new\n> > CameraCapabilities class.\n> >\n> > Break out from the camera_device.cpp file all the functions relative to:\n> > - Initialization of supported stream configurations\n> > - Initialization of static metadata\n> > - Initialization of request templates\n> >\n> > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n> > ---\n> >  src/android/camera_capabilities.cpp | 1165 +++++++++++++++++++++++++++\n> >  src/android/camera_capabilities.h   |   64 ++\n> >  src/android/camera_device.cpp       | 1147 +-------------------------\n> >  src/android/camera_device.h         |   27 +-\n> >  src/android/meson.build             |    1 +\n> >  5 files changed, 1245 insertions(+), 1159 deletions(-)\n> >  create mode 100644 src/android/camera_capabilities.cpp\n> >  create mode 100644 src/android/camera_capabilities.h\n> >\n> > diff --git a/src/android/camera_capabilities.cpp b/src/android/camera_capabilities.cpp\n> > new file mode 100644\n> > index 000000000000..20df9a6f1abb\n> > --- /dev/null\n> > +++ b/src/android/camera_capabilities.cpp\n> > @@ -0,0 +1,1165 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2021, Google Inc.\n> > + *\n> > + * camera_capabilities.cpp - Camera static properties manager\n> > + */\n> > +\n> > +#include \"camera_capabilities.h\"\n> > +\n> > +#include <array>\n> > +#include <cmath>\n> > +\n> > +#include <hardware/camera3.h>\n> > +\n> > +#include <libcamera/control_ids.h>\n> > +#include <libcamera/controls.h>\n> > +#include <libcamera/formats.h>\n> > +#include <libcamera/property_ids.h>\n> > +\n> > +#include \"libcamera/internal/formats.h\"\n> > +#include \"libcamera/internal/log.h\"\n> > +\n> > +using namespace libcamera;\n> > +\n> > +LOG_DECLARE_CATEGORY(HAL)\n> > +\n> > +namespace {\n> > +\n> > +/*\n> > + * \\var camera3Resolutions\n> > + * \\brief The list of image resolutions defined as mandatory to be supported by\n> > + * the Android Camera3 specification\n> > + */\n> > +const std::vector<Size> camera3Resolutions = {\n> > +\t{ 320, 240 },\n> > +\t{ 640, 480 },\n> > +\t{ 1280, 720 },\n> > +\t{ 1920, 1080 }\n> > +};\n> > +\n> > +/*\n> > + * \\struct Camera3Format\n> > + * \\brief Data associated with an Android format identifier\n> > + * \\var libcameraFormats List of libcamera pixel formats compatible with the\n> > + * Android format\n> > + * \\var name The human-readable representation of the Android format code\n> > + */\n> > +struct Camera3Format {\n> > +\tstd::vector<PixelFormat> libcameraFormats;\n> > +\tbool mandatory;\n> > +\tconst char *name;\n> > +};\n> > +\n> > +/*\n> > + * \\var camera3FormatsMap\n> > + * \\brief Associate Android format code with ancillary data\n> > + */\n> > +const std::map<int, const Camera3Format> camera3FormatsMap = {\n> > +\t{\n> > +\t\tHAL_PIXEL_FORMAT_BLOB, {\n> > +\t\t\t{ formats::MJPEG },\n> > +\t\t\ttrue,\n> > +\t\t\t\"BLOB\"\n> > +\t\t}\n> > +\t}, {\n> > +\t\tHAL_PIXEL_FORMAT_YCbCr_420_888, {\n> > +\t\t\t{ formats::NV12, formats::NV21 },\n> > +\t\t\ttrue,\n> > +\t\t\t\"YCbCr_420_888\"\n> > +\t\t}\n> > +\t}, {\n> > +\t\t/*\n> > +\t\t * \\todo Translate IMPLEMENTATION_DEFINED inspecting the gralloc\n> > +\t\t * usage flag. For now, copy the YCbCr_420 configuration.\n> > +\t\t */\n> > +\t\tHAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, {\n> > +\t\t\t{ formats::NV12, formats::NV21 },\n> > +\t\t\ttrue,\n> > +\t\t\t\"IMPLEMENTATION_DEFINED\"\n> > +\t\t}\n> > +\t}, {\n> > +\t\tHAL_PIXEL_FORMAT_RAW10, {\n> > +\t\t\t{\n> > +\t\t\t\tformats::SBGGR10_CSI2P,\n> > +\t\t\t\tformats::SGBRG10_CSI2P,\n> > +\t\t\t\tformats::SGRBG10_CSI2P,\n> > +\t\t\t\tformats::SRGGB10_CSI2P\n> > +\t\t\t},\n> > +\t\t\tfalse,\n> > +\t\t\t\"RAW10\"\n> > +\t\t}\n> > +\t}, {\n> > +\t\tHAL_PIXEL_FORMAT_RAW12, {\n> > +\t\t\t{\n> > +\t\t\t\tformats::SBGGR12_CSI2P,\n> > +\t\t\t\tformats::SGBRG12_CSI2P,\n> > +\t\t\t\tformats::SGRBG12_CSI2P,\n> > +\t\t\t\tformats::SRGGB12_CSI2P\n> > +\t\t\t},\n> > +\t\t\tfalse,\n> > +\t\t\t\"RAW12\"\n> > +\t\t}\n> > +\t}, {\n> > +\t\tHAL_PIXEL_FORMAT_RAW16, {\n> > +\t\t\t{\n> > +\t\t\t\tformats::SBGGR16,\n> > +\t\t\t\tformats::SGBRG16,\n> > +\t\t\t\tformats::SGRBG16,\n> > +\t\t\t\tformats::SRGGB16\n> > +\t\t\t},\n> > +\t\t\tfalse,\n> > +\t\t\t\"RAW16\"\n> > +\t\t}\n> > +\t},\n> > +};\n> > +\n> > +} /* namespace */\n> > +\n> > +int CameraCapabilities::initialize(std::shared_ptr<libcamera::Camera> camera,\n> > +\t\t\t\t   int orientation, int facing)\n> > +{\n> > +\tcamera_ = camera;\n> > +\torientation_ = orientation;\n> > +\tfacing_ = facing;\n> > +\n> > +\t/* Acquire the camera and initialize available stream configurations. */\n> > +\tint ret = camera_->acquire();\n> > +\tif (ret) {\n> > +\t\tLOG(HAL, Error) << \"Failed to temporarily acquire the camera\";\n> > +\t\treturn ret;\n> > +\t}\n> > +\n> > +\tret = initializeStreamConfigurations();\n> > +\tcamera_->release();\n> > +\tif (ret)\n> > +\t\treturn ret;\n> > +\n> > +\treturn initializeStaticMetadata();\n> > +}\n> > +\n> > +std::vector<Size> CameraCapabilities::getYUVResolutions(CameraConfiguration *cameraConfig,\n> > +\t\t\t\t\t\t\tconst PixelFormat &pixelFormat,\n> > +\t\t\t\t\t\t\tconst std::vector<Size> &resolutions)\n> > +{\n> > +\tstd::vector<Size> supportedResolutions;\n> > +\n> > +\tStreamConfiguration &cfg = cameraConfig->at(0);\n> > +\tfor (const Size &res : resolutions) {\n> > +\t\tcfg.pixelFormat = pixelFormat;\n> > +\t\tcfg.size = res;\n> > +\n> > +\t\tCameraConfiguration::Status status = cameraConfig->validate();\n> > +\t\tif (status != CameraConfiguration::Valid) {\n> > +\t\t\tLOG(HAL, Debug) << cfg.toString() << \" not supported\";\n> > +\t\t\tcontinue;\n> > +\t\t}\n> > +\n> > +\t\tLOG(HAL, Debug) << cfg.toString() << \" supported\";\n> > +\n> > +\t\tsupportedResolutions.push_back(res);\n> > +\t}\n> > +\n> > +\treturn supportedResolutions;\n> > +}\n> > +\n> > +std::vector<Size> CameraCapabilities::getRawResolutions(const libcamera::PixelFormat &pixelFormat)\n> > +{\n> > +\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> > +\t\tcamera_->generateConfiguration({ StreamRole::Raw });\n> > +\tStreamConfiguration &cfg = cameraConfig->at(0);\n> > +\tconst StreamFormats &formats = cfg.formats();\n> > +\tstd::vector<Size> supportedResolutions = formats.sizes(pixelFormat);\n> > +\n> > +\treturn supportedResolutions;\n> > +}\n> > +\n> > +/*\n> > + * Initialize the format conversion map to translate from Android format\n> > + * identifier to libcamera pixel formats and fill in the list of supported\n> > + * stream configurations to be reported to the Android camera framework through\n> > + * the Camera static metadata.\n> > + */\n> > +int CameraCapabilities::initializeStreamConfigurations()\n> > +{\n> > +\t/*\n> > +\t * Get the maximum output resolutions\n> > +\t * \\todo Get this from the camera properties once defined\n> > +\t */\n> > +\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> > +\t\tcamera_->generateConfiguration({ StillCapture });\n> > +\tif (!cameraConfig) {\n> > +\t\tLOG(HAL, Error) << \"Failed to get maximum resolution\";\n> > +\t\treturn -EINVAL;\n> > +\t}\n> > +\tStreamConfiguration &cfg = cameraConfig->at(0);\n> > +\n> > +\t/*\n> > +\t * \\todo JPEG - Adjust the maximum available resolution by taking the\n> > +\t * JPEG encoder requirements into account (alignment and aspect ratio).\n> > +\t */\n> > +\tconst Size maxRes = cfg.size;\n> > +\tLOG(HAL, Debug) << \"Maximum supported resolution: \" << maxRes.toString();\n> > +\n> > +\t/*\n> > +\t * Build the list of supported image resolutions.\n> > +\t *\n> > +\t * The resolutions listed in camera3Resolution are mandatory to be\n> > +\t * supported, up to the camera maximum resolution.\n> > +\t *\n> > +\t * Augment the list by adding resolutions calculated from the camera\n> > +\t * maximum one.\n> > +\t */\n> > +\tstd::vector<Size> cameraResolutions;\n> > +\tstd::copy_if(camera3Resolutions.begin(), camera3Resolutions.end(),\n> > +\t\t     std::back_inserter(cameraResolutions),\n> > +\t\t     [&](const Size &res) { return res < maxRes; });\n> > +\n> > +\t/*\n> > +\t * The Camera3 specification suggests adding 1/2 and 1/4 of the maximum\n> > +\t * resolution.\n> > +\t */\n> > +\tfor (unsigned int divider = 2;; divider <<= 1) {\n> > +\t\tSize derivedSize{\n> > +\t\t\tmaxRes.width / divider,\n> > +\t\t\tmaxRes.height / divider,\n> > +\t\t};\n> > +\n> > +\t\tif (derivedSize.width < 320 ||\n> > +\t\t    derivedSize.height < 240)\n> > +\t\t\tbreak;\n> > +\n> > +\t\tcameraResolutions.push_back(derivedSize);\n> > +\t}\n> > +\tcameraResolutions.push_back(maxRes);\n> > +\n> > +\t/* Remove duplicated entries from the list of supported resolutions. */\n> > +\tstd::sort(cameraResolutions.begin(), cameraResolutions.end());\n> > +\tauto last = std::unique(cameraResolutions.begin(), cameraResolutions.end());\n> > +\tcameraResolutions.erase(last, cameraResolutions.end());\n> > +\n> > +\t/*\n> > +\t * Build the list of supported camera formats.\n> > +\t *\n> > +\t * To each Android format a list of compatible libcamera formats is\n> > +\t * associated. The first libcamera format that tests successful is added\n> > +\t * to the format translation map used when configuring the streams.\n> > +\t * It is then tested against the list of supported camera resolutions to\n> > +\t * build the stream configuration map reported through the camera static\n> > +\t * metadata.\n> > +\t */\n> > +\tSize maxJpegSize;\n> > +\tfor (const auto &format : camera3FormatsMap) {\n> > +\t\tint androidFormat = format.first;\n> > +\t\tconst Camera3Format &camera3Format = format.second;\n> > +\t\tconst std::vector<PixelFormat> &libcameraFormats =\n> > +\t\t\tcamera3Format.libcameraFormats;\n> > +\n> > +\t\tLOG(HAL, Debug) << \"Trying to map Android format \"\n> > +\t\t\t\t<< camera3Format.name;\n> > +\n> > +\t\t/*\n> > +\t\t * JPEG is always supported, either produced directly by the\n> > +\t\t * camera, or encoded in the HAL.\n> > +\t\t */\n> > +\t\tif (androidFormat == HAL_PIXEL_FORMAT_BLOB) {\n> > +\t\t\tformatsMap_[androidFormat] = formats::MJPEG;\n> > +\t\t\tLOG(HAL, Debug) << \"Mapped Android format \"\n> > +\t\t\t\t\t<< camera3Format.name << \" to \"\n> > +\t\t\t\t\t<< formats::MJPEG.toString()\n> > +\t\t\t\t\t<< \" (fixed mapping)\";\n> > +\t\t\tcontinue;\n> > +\t\t}\n> > +\n> > +\t\t/*\n> > +\t\t * Test the libcamera formats that can produce images\n> > +\t\t * compatible with the format defined by Android.\n> > +\t\t */\n> > +\t\tPixelFormat mappedFormat;\n> > +\t\tfor (const PixelFormat &pixelFormat : libcameraFormats) {\n> > +\n> > +\t\t\tLOG(HAL, Debug) << \"Testing \" << pixelFormat.toString();\n> > +\n> > +\t\t\t/*\n> > +\t\t\t * The stream configuration size can be adjusted,\n> > +\t\t\t * not the pixel format.\n> > +\t\t\t *\n> > +\t\t\t * \\todo This could be simplified once all pipeline\n> > +\t\t\t * handlers will report the StreamFormats list of\n> > +\t\t\t * supported formats.\n> > +\t\t\t */\n> > +\t\t\tcfg.pixelFormat = pixelFormat;\n> > +\n> > +\t\t\tCameraConfiguration::Status status = cameraConfig->validate();\n> > +\t\t\tif (status != CameraConfiguration::Invalid &&\n> > +\t\t\t    cfg.pixelFormat == pixelFormat) {\n> > +\t\t\t\tmappedFormat = pixelFormat;\n> > +\t\t\t\tbreak;\n> > +\t\t\t}\n> > +\t\t}\n> > +\n> > +\t\tif (!mappedFormat.isValid()) {\n> > +\t\t\t/* If the format is not mandatory, skip it. */\n> > +\t\t\tif (!camera3Format.mandatory)\n> > +\t\t\t\tcontinue;\n> > +\n> > +\t\t\tLOG(HAL, Error)\n> > +\t\t\t\t<< \"Failed to map mandatory Android format \"\n> > +\t\t\t\t<< camera3Format.name << \" (\"\n> > +\t\t\t\t<< utils::hex(androidFormat) << \"): aborting\";\n> > +\t\t\treturn -EINVAL;\n> > +\t\t}\n> > +\n> > +\t\t/*\n> > +\t\t * Record the mapping and then proceed to generate the\n> > +\t\t * stream configurations map, by testing the image resolutions.\n> > +\t\t */\n> > +\t\tformatsMap_[androidFormat] = mappedFormat;\n> > +\t\tLOG(HAL, Debug) << \"Mapped Android format \"\n> > +\t\t\t\t<< camera3Format.name << \" to \"\n> > +\t\t\t\t<< mappedFormat.toString();\n> > +\n> > +\t\tstd::vector<Size> resolutions;\n> > +\t\tconst PixelFormatInfo &info = PixelFormatInfo::info(mappedFormat);\n> > +\t\tif (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW)\n> > +\t\t\tresolutions = getRawResolutions(mappedFormat);\n> > +\t\telse\n> > +\t\t\tresolutions = getYUVResolutions(cameraConfig.get(),\n> > +\t\t\t\t\t\t\tmappedFormat,\n> > +\t\t\t\t\t\t\tcameraResolutions);\n> > +\n> > +\t\tfor (const Size &res : resolutions) {\n> > +\t\t\tstreamConfigurations_.push_back({ res, androidFormat });\n> > +\n> > +\t\t\t/*\n> > +\t\t\t * If the format is HAL_PIXEL_FORMAT_YCbCr_420_888\n> > +\t\t\t * from which JPEG is produced, add an entry for\n> > +\t\t\t * the JPEG stream.\n> > +\t\t\t *\n> > +\t\t\t * \\todo Wire the JPEG encoder to query the supported\n> > +\t\t\t * sizes provided a list of formats it can encode.\n> > +\t\t\t *\n> > +\t\t\t * \\todo Support JPEG streams produced by the Camera\n> > +\t\t\t * natively.\n> > +\t\t\t */\n> > +\t\t\tif (androidFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {\n> > +\t\t\t\tstreamConfigurations_.push_back(\n> > +\t\t\t\t\t{ res, HAL_PIXEL_FORMAT_BLOB });\n> > +\t\t\t\tmaxJpegSize = std::max(maxJpegSize, res);\n> > +\t\t\t}\n> > +\t\t}\n> > +\n> > +\t\t/*\n> > +\t\t * \\todo Calculate the maximum JPEG buffer size by asking the\n> > +\t\t * encoder giving the maximum frame size required.\n> > +\t\t */\n> > +\t\tmaxJpegBufferSize_ = maxJpegSize.width * maxJpegSize.height * 1.5;\n> > +\t}\n> > +\n> > +\tLOG(HAL, Debug) << \"Collected stream configuration map: \";\n> > +\tfor (const auto &entry : streamConfigurations_)\n> > +\t\tLOG(HAL, Debug) << \"{ \" << entry.resolution.toString() << \" - \"\n> > +\t\t\t\t<< utils::hex(entry.androidFormat) << \" }\";\n> > +\n> > +\treturn 0;\n> > +}\n> > +\n> > +int CameraCapabilities::initializeStaticMetadata()\n> > +{\n> > +\tstaticMetadata_ = std::make_unique<CameraMetadata>(64, 1024);\n> > +\tif (!staticMetadata_->isValid()) {\n> > +\t\tLOG(HAL, Error) << \"Failed to allocate static metadata\";\n> > +\t\tstaticMetadata_.reset();\n> > +\t\treturn -EINVAL;\n> > +\t}\n> > +\n> > +\tconst ControlInfoMap &controlsInfo = camera_->controls();\n> > +\tconst ControlList &properties = camera_->properties();\n> > +\n> > +\t/* Color correction static metadata. */\n> > +\t{\n> > +\t\tstd::vector<uint8_t> data;\n> > +\t\tdata.reserve(3);\n> > +\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::ColorCorrectionAberrationMode);\n> > +\t\tif (infoMap != controlsInfo.end()) {\n> > +\t\t\tfor (const auto &value : infoMap->second.values())\n> > +\t\t\t\tdata.push_back(value.get<int32_t>());\n> > +\t\t} else {\n> > +\t\t\tdata.push_back(ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF);\n> > +\t\t}\n> > +\t\tstaticMetadata_->addEntry(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,\n> > +\t\t\t\t\t  data);\n> > +\t}\n> > +\n> > +\t/* Control static metadata. */\n> > +\tstd::vector<uint8_t> aeAvailableAntiBandingModes = {\n> > +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF,\n> > +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ,\n> > +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ,\n> > +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO,\n> > +\t};\n> > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,\n> > +\t\t\t\t  aeAvailableAntiBandingModes);\n> > +\n> > +\tstd::vector<uint8_t> aeAvailableModes = {\n> > +\t\tANDROID_CONTROL_AE_MODE_ON,\n> > +\t};\n> > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_MODES,\n> > +\t\t\t\t  aeAvailableModes);\n> > +\n> > +\tint64_t minFrameDurationNsec = -1;\n> > +\tint64_t maxFrameDurationNsec = -1;\n> > +\tconst auto frameDurationsInfo = controlsInfo.find(&controls::FrameDurationLimits);\n> > +\tif (frameDurationsInfo != controlsInfo.end()) {\n> > +\t\tminFrameDurationNsec = frameDurationsInfo->second.min().get<int64_t>() * 1000;\n> > +\t\tmaxFrameDurationNsec = frameDurationsInfo->second.max().get<int64_t>() * 1000;\n> > +\n> > +\t\t/*\n> > +\t\t * Adjust the minimum frame duration to comply with Android\n> > +\t\t * requirements. The camera service mandates all preview/record\n> > +\t\t * streams to have a minimum frame duration < 33,366 milliseconds\n> > +\t\t * (see MAX_PREVIEW_RECORD_DURATION_NS in the camera service\n> > +\t\t * implementation).\n> > +\t\t *\n> > +\t\t * If we're close enough (+ 500 useconds) to that value, round\n> > +\t\t * the minimum frame duration of the camera to an accepted\n> > +\t\t * value.\n> > +\t\t */\n> > +\t\tstatic constexpr int64_t MAX_PREVIEW_RECORD_DURATION_NS = 1e9 / 29.97;\n> > +\t\tif (minFrameDurationNsec > MAX_PREVIEW_RECORD_DURATION_NS &&\n> > +\t\t    minFrameDurationNsec < MAX_PREVIEW_RECORD_DURATION_NS + 500000)\n> > +\t\t\tminFrameDurationNsec = MAX_PREVIEW_RECORD_DURATION_NS - 1000;\n> > +\n> > +\t\t/*\n> > +\t\t * The AE routine frame rate limits are computed using the frame\n> > +\t\t * duration limits, as libcamera clips the AE routine to the\n> > +\t\t * frame durations.\n> > +\t\t */\n> > +\t\tint32_t maxFps = std::round(1e9 / minFrameDurationNsec);\n> > +\t\tint32_t minFps = std::round(1e9 / maxFrameDurationNsec);\n> > +\t\tminFps = std::max(1, minFps);\n> > +\n> > +\t\t/*\n> > +\t\t * Force rounding errors so that we have the proper frame\n> > +\t\t * durations for when we reuse these variables later\n> > +\t\t */\n> > +\t\tminFrameDurationNsec = 1e9 / maxFps;\n> > +\t\tmaxFrameDurationNsec = 1e9 / minFps;\n> > +\n> > +\t\t/*\n> > +\t\t * Register to the camera service {min, max} and {max, max}\n> > +\t\t * intervals as requested by the metadata documentation.\n> > +\t\t */\n> > +\t\tint32_t availableAeFpsTarget[] = {\n> > +\t\t\tminFps, maxFps, maxFps, maxFps\n> > +\t\t};\n> > +\t\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> > +\t\t\t\t\t  availableAeFpsTarget);\n> > +\t}\n> > +\n> > +\tstd::vector<int32_t> aeCompensationRange = {\n> > +\t\t0, 0,\n> > +\t};\n> > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_RANGE,\n> > +\t\t\t\t  aeCompensationRange);\n> > +\n> > +\tconst camera_metadata_rational_t aeCompensationStep[] = {\n> > +\t\t{ 0, 1 }\n> > +\t};\n> > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_STEP,\n> > +\t\t\t\t  aeCompensationStep);\n> > +\n> > +\tstd::vector<uint8_t> availableAfModes = {\n> > +\t\tANDROID_CONTROL_AF_MODE_OFF,\n> > +\t};\n> > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AF_AVAILABLE_MODES,\n> > +\t\t\t\t  availableAfModes);\n> > +\n> > +\tstd::vector<uint8_t> availableEffects = {\n> > +\t\tANDROID_CONTROL_EFFECT_MODE_OFF,\n> > +\t};\n> > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_EFFECTS,\n> > +\t\t\t\t  availableEffects);\n> > +\n> > +\tstd::vector<uint8_t> availableSceneModes = {\n> > +\t\tANDROID_CONTROL_SCENE_MODE_DISABLED,\n> > +\t};\n> > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_SCENE_MODES,\n> > +\t\t\t\t  availableSceneModes);\n> > +\n> > +\tstd::vector<uint8_t> availableStabilizationModes = {\n> > +\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF,\n> > +\t};\n> > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,\n> > +\t\t\t\t  availableStabilizationModes);\n> > +\n> > +\t/*\n> > +\t * \\todo Inspect the Camera capabilities to report the available\n> > +\t * AWB modes. Default to AUTO as CTS tests require it.\n> > +\t */\n> > +\tstd::vector<uint8_t> availableAwbModes = {\n> > +\t\tANDROID_CONTROL_AWB_MODE_AUTO,\n> > +\t};\n> > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AWB_AVAILABLE_MODES,\n> > +\t\t\t\t  availableAwbModes);\n> > +\n> > +\tstd::vector<int32_t> availableMaxRegions = {\n> > +\t\t0, 0, 0,\n> > +\t};\n> > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_MAX_REGIONS,\n> > +\t\t\t\t  availableMaxRegions);\n> > +\n> > +\tstd::vector<uint8_t> sceneModesOverride = {\n> > +\t\tANDROID_CONTROL_AE_MODE_ON,\n> > +\t\tANDROID_CONTROL_AWB_MODE_AUTO,\n> > +\t\tANDROID_CONTROL_AF_MODE_OFF,\n> > +\t};\n> > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_SCENE_MODE_OVERRIDES,\n> > +\t\t\t\t  sceneModesOverride);\n> > +\n> > +\tuint8_t aeLockAvailable = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE;\n> > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE,\n> > +\t\t\t\t  aeLockAvailable);\n> > +\n> > +\tuint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;\n> > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> > +\t\t\t\t  awbLockAvailable);\n> > +\n> > +\tchar availableControlModes = ANDROID_CONTROL_MODE_AUTO;\n> > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_MODES,\n> > +\t\t\t\t  availableControlModes);\n> > +\n> > +\t/* JPEG static metadata. */\n> > +\n> > +\t/*\n> > +\t * Create the list of supported thumbnail sizes by inspecting the\n> > +\t * available JPEG resolutions collected in streamConfigurations_ and\n> > +\t * generate one entry for each aspect ratio.\n> > +\t *\n> > +\t * The JPEG thumbnailer can freely scale, so pick an arbitrary\n> > +\t * (160, 160) size as the bounding rectangle, which is then cropped to\n> > +\t * the different supported aspect ratios.\n> > +\t */\n> > +\tconstexpr Size maxJpegThumbnail(160, 160);\n> > +\tstd::vector<Size> thumbnailSizes;\n> > +\tthumbnailSizes.push_back({ 0, 0 });\n> > +\tfor (const auto &entry : streamConfigurations_) {\n> > +\t\tif (entry.androidFormat != HAL_PIXEL_FORMAT_BLOB)\n> > +\t\t\tcontinue;\n> > +\n> > +\t\tSize thumbnailSize = maxJpegThumbnail\n> > +\t\t\t\t     .boundedToAspectRatio({ entry.resolution.width,\n> > +\t\t\t\t\t\t\t     entry.resolution.height });\n> > +\t\tthumbnailSizes.push_back(thumbnailSize);\n> > +\t}\n> > +\n> > +\tstd::sort(thumbnailSizes.begin(), thumbnailSizes.end());\n> > +\tauto last = std::unique(thumbnailSizes.begin(), thumbnailSizes.end());\n> > +\tthumbnailSizes.erase(last, thumbnailSizes.end());\n> > +\n> > +\t/* Transform sizes in to a list of integers that can be consumed. */\n> > +\tstd::vector<int32_t> thumbnailEntries;\n> > +\tthumbnailEntries.reserve(thumbnailSizes.size() * 2);\n> > +\tfor (const auto &size : thumbnailSizes) {\n> > +\t\tthumbnailEntries.push_back(size.width);\n> > +\t\tthumbnailEntries.push_back(size.height);\n> > +\t}\n> > +\tstaticMetadata_->addEntry(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,\n> > +\t\t\t\t  thumbnailEntries);\n> > +\n> > +\tstaticMetadata_->addEntry(ANDROID_JPEG_MAX_SIZE, maxJpegBufferSize_);\n> > +\n> > +\t/* Sensor static metadata. */\n> > +\tstd::array<int32_t, 2> pixelArraySize;\n> > +\t{\n> > +\t\tconst Size &size = properties.get(properties::PixelArraySize);\n> > +\t\tpixelArraySize[0] = size.width;\n> > +\t\tpixelArraySize[1] = size.height;\n> > +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,\n> > +\t\t\t\t\t  pixelArraySize);\n> > +\t}\n> > +\n> > +\tif (properties.contains(properties::UnitCellSize)) {\n> > +\t\tconst Size &cellSize = properties.get<Size>(properties::UnitCellSize);\n> > +\t\tstd::array<float, 2> physicalSize{\n> > +\t\t\tcellSize.width * pixelArraySize[0] / 1e6f,\n> > +\t\t\tcellSize.height * pixelArraySize[1] / 1e6f\n> > +\t\t};\n> > +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,\n> > +\t\t\t\t\t  physicalSize);\n> > +\t}\n> > +\n> > +\t{\n> > +\t\tconst Span<const Rectangle> &rects =\n> > +\t\t\tproperties.get(properties::PixelArrayActiveAreas);\n> > +\t\tstd::vector<int32_t> data{\n> > +\t\t\tstatic_cast<int32_t>(rects[0].x),\n> > +\t\t\tstatic_cast<int32_t>(rects[0].y),\n> > +\t\t\tstatic_cast<int32_t>(rects[0].width),\n> > +\t\t\tstatic_cast<int32_t>(rects[0].height),\n> > +\t\t};\n> > +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,\n> > +\t\t\t\t\t  data);\n> > +\t}\n> > +\n> > +\tint32_t sensitivityRange[] = {\n> > +\t\t32, 2400,\n> > +\t};\n> > +\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,\n> > +\t\t\t\t  sensitivityRange);\n> > +\n> > +\t/* Report the color filter arrangement if the camera reports it. */\n> > +\tif (properties.contains(properties::draft::ColorFilterArrangement)) {\n> > +\t\tuint8_t filterArr = properties.get(properties::draft::ColorFilterArrangement);\n> > +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,\n> > +\t\t\t\t\t  filterArr);\n> > +\t}\n> > +\n> > +\tconst auto &exposureInfo = controlsInfo.find(&controls::ExposureTime);\n> > +\tif (exposureInfo != controlsInfo.end()) {\n> > +\t\tint64_t exposureTimeRange[2] = {\n> > +\t\t\texposureInfo->second.min().get<int32_t>() * 1000LL,\n> > +\t\t\texposureInfo->second.max().get<int32_t>() * 1000LL,\n> > +\t\t};\n> > +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,\n> > +\t\t\t\t\t  exposureTimeRange, 2);\n> > +\t}\n> > +\n> > +\tstaticMetadata_->addEntry(ANDROID_SENSOR_ORIENTATION, orientation_);\n> > +\n> > +\tstd::vector<int32_t> testPatternModes = {\n> > +\t\tANDROID_SENSOR_TEST_PATTERN_MODE_OFF\n> > +\t};\n> > +\tconst auto &testPatternsInfo =\n> > +\t\tcontrolsInfo.find(&controls::draft::TestPatternMode);\n> > +\tif (testPatternsInfo != controlsInfo.end()) {\n> > +\t\tconst auto &values = testPatternsInfo->second.values();\n> > +\t\tASSERT(!values.empty());\n> > +\t\tfor (const auto &value : values) {\n> > +\t\t\tswitch (value.get<int32_t>()) {\n> > +\t\t\tcase controls::draft::TestPatternModeOff:\n> > +\t\t\t\t/*\n> > +\t\t\t\t * ANDROID_SENSOR_TEST_PATTERN_MODE_OFF is\n> > +\t\t\t\t * already in testPatternModes.\n> > +\t\t\t\t */\n> > +\t\t\t\tbreak;\n> > +\n> > +\t\t\tcase controls::draft::TestPatternModeSolidColor:\n> > +\t\t\t\ttestPatternModes.push_back(\n> > +\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR);\n> > +\t\t\t\tbreak;\n> > +\n> > +\t\t\tcase controls::draft::TestPatternModeColorBars:\n> > +\t\t\t\ttestPatternModes.push_back(\n> > +\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS);\n> > +\t\t\t\tbreak;\n> > +\n> > +\t\t\tcase controls::draft::TestPatternModeColorBarsFadeToGray:\n> > +\t\t\t\ttestPatternModes.push_back(\n> > +\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY);\n> > +\t\t\t\tbreak;\n> > +\n> > +\t\t\tcase controls::draft::TestPatternModePn9:\n> > +\t\t\t\ttestPatternModes.push_back(\n> > +\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_PN9);\n> > +\t\t\t\tbreak;\n> > +\n> > +\t\t\tcase controls::draft::TestPatternModeCustom1:\n> > +\t\t\t\t/* We don't support this yet. */\n> > +\t\t\t\tbreak;\n> > +\n> > +\t\t\tdefault:\n> > +\t\t\t\tLOG(HAL, Error) << \"Unknown test pattern mode: \"\n> > +\t\t\t\t\t\t<< value.get<int32_t>();\n> > +\t\t\t\tcontinue;\n> > +\t\t\t}\n> > +\t\t}\n> > +\t}\n> > +\tstaticMetadata_->addEntry(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,\n> > +\t\t\t\t  testPatternModes);\n> > +\n> > +\tuint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;\n> > +\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,\n> > +\t\t\t\t  timestampSource);\n> > +\n> > +\tif (maxFrameDurationNsec > 0)\n> > +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,\n> > +\t\t\t\t\t  maxFrameDurationNsec);\n> > +\n> > +\t/* Statistics static metadata. */\n> > +\tuint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;\n> > +\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,\n> > +\t\t\t\t  faceDetectMode);\n> > +\n> > +\tint32_t maxFaceCount = 0;\n> > +\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,\n> > +\t\t\t\t  maxFaceCount);\n> > +\n> > +\t{\n> > +\t\tstd::vector<uint8_t> data;\n> > +\t\tdata.reserve(2);\n> > +\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::LensShadingMapMode);\n> > +\t\tif (infoMap != controlsInfo.end()) {\n> > +\t\t\tfor (const auto &value : infoMap->second.values())\n> > +\t\t\t\tdata.push_back(value.get<int32_t>());\n> > +\t\t} else {\n> > +\t\t\tdata.push_back(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF);\n> > +\t\t}\n> > +\t\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,\n> > +\t\t\t\t\t  data);\n> > +\t}\n> > +\n> > +\t/* Sync static metadata. */\n> > +\tint32_t maxLatency = ANDROID_SYNC_MAX_LATENCY_UNKNOWN;\n> > +\tstaticMetadata_->addEntry(ANDROID_SYNC_MAX_LATENCY, maxLatency);\n> > +\n> > +\t/* Flash static metadata. */\n> > +\tchar flashAvailable = ANDROID_FLASH_INFO_AVAILABLE_FALSE;\n> > +\tstaticMetadata_->addEntry(ANDROID_FLASH_INFO_AVAILABLE,\n> > +\t\t\t\t  flashAvailable);\n> > +\n> > +\t/* Lens static metadata. */\n> > +\tstd::vector<float> lensApertures = {\n> > +\t\t2.53 / 100,\n> > +\t};\n> > +\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_APERTURES,\n> > +\t\t\t\t  lensApertures);\n> > +\n> > +\tuint8_t lensFacing;\n> > +\tswitch (facing_) {\n> > +\tdefault:\n> > +\tcase CAMERA_FACING_FRONT:\n> > +\t\tlensFacing = ANDROID_LENS_FACING_FRONT;\n> > +\t\tbreak;\n> > +\tcase CAMERA_FACING_BACK:\n> > +\t\tlensFacing = ANDROID_LENS_FACING_BACK;\n> > +\t\tbreak;\n> > +\tcase CAMERA_FACING_EXTERNAL:\n> > +\t\tlensFacing = ANDROID_LENS_FACING_EXTERNAL;\n> > +\t\tbreak;\n> > +\t}\n> > +\tstaticMetadata_->addEntry(ANDROID_LENS_FACING, lensFacing);\n> > +\n> > +\tstd::vector<float> lensFocalLengths = {\n> > +\t\t1,\n> > +\t};\n> > +\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,\n> > +\t\t\t\t  lensFocalLengths);\n> > +\n> > +\tstd::vector<uint8_t> opticalStabilizations = {\n> > +\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF,\n> > +\t};\n> > +\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,\n> > +\t\t\t\t  opticalStabilizations);\n> > +\n> > +\tfloat hypeFocalDistance = 0;\n> > +\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,\n> > +\t\t\t\t  hypeFocalDistance);\n> > +\n> > +\tfloat minFocusDistance = 0;\n> > +\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,\n> > +\t\t\t\t  minFocusDistance);\n> > +\n> > +\t/* Noise reduction modes. */\n> > +\t{\n> > +\t\tstd::vector<uint8_t> data;\n> > +\t\tdata.reserve(5);\n> > +\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::NoiseReductionMode);\n> > +\t\tif (infoMap != controlsInfo.end()) {\n> > +\t\t\tfor (const auto &value : infoMap->second.values())\n> > +\t\t\t\tdata.push_back(value.get<int32_t>());\n> > +\t\t} else {\n> > +\t\t\tdata.push_back(ANDROID_NOISE_REDUCTION_MODE_OFF);\n> > +\t\t}\n> > +\t\tstaticMetadata_->addEntry(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,\n> > +\t\t\t\t\t  data);\n> > +\t}\n> > +\n> > +\t/* Scaler static metadata. */\n> > +\n> > +\t/*\n> > +\t * \\todo The digital zoom factor is a property that depends on the\n> > +\t * desired output configuration and the sensor frame size input to the\n> > +\t * ISP. This information is not available to the Android HAL, not at\n> > +\t * initialization time at least.\n> > +\t *\n> > +\t * As a workaround rely on pipeline handlers initializing the\n> > +\t * ScalerCrop control with the camera default configuration and use the\n> > +\t * maximum and minimum crop rectangles to calculate the digital zoom\n> > +\t * factor.\n> > +\t */\n> > +\tfloat maxZoom = 1.0f;\n> > +\tconst auto scalerCrop = controlsInfo.find(&controls::ScalerCrop);\n> > +\tif (scalerCrop != controlsInfo.end()) {\n> > +\t\tRectangle min = scalerCrop->second.min().get<Rectangle>();\n> > +\t\tRectangle max = scalerCrop->second.max().get<Rectangle>();\n> > +\t\tmaxZoom = std::min(1.0f * max.width / min.width,\n> > +\t\t\t\t   1.0f * max.height / min.height);\n> > +\t}\n> > +\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,\n> > +\t\t\t\t  maxZoom);\n> > +\n> > +\tstd::vector<uint32_t> availableStreamConfigurations;\n> > +\tavailableStreamConfigurations.reserve(streamConfigurations_.size() * 4);\n> > +\tfor (const auto &entry : streamConfigurations_) {\n> > +\t\tavailableStreamConfigurations.push_back(entry.androidFormat);\n> > +\t\tavailableStreamConfigurations.push_back(entry.resolution.width);\n> > +\t\tavailableStreamConfigurations.push_back(entry.resolution.height);\n> > +\t\tavailableStreamConfigurations.push_back(\n> > +\t\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);\n> > +\t}\n> > +\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,\n> > +\t\t\t\t  availableStreamConfigurations);\n> > +\n> > +\tstd::vector<int64_t> availableStallDurations = {\n> > +\t\tANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920, 33333333,\n> > +\t};\n> > +\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,\n> > +\t\t\t\t  availableStallDurations);\n> > +\n> > +\t/* Use the minimum frame duration for all the YUV/RGB formats. */\n> > +\tif (minFrameDurationNsec > 0) {\n> > +\t\tstd::vector<int64_t> minFrameDurations;\n> > +\t\tminFrameDurations.reserve(streamConfigurations_.size() * 4);\n> > +\t\tfor (const auto &entry : streamConfigurations_) {\n> > +\t\t\tminFrameDurations.push_back(entry.androidFormat);\n> > +\t\t\tminFrameDurations.push_back(entry.resolution.width);\n> > +\t\t\tminFrameDurations.push_back(entry.resolution.height);\n> > +\t\t\tminFrameDurations.push_back(minFrameDurationNsec);\n> > +\t\t}\n> > +\t\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,\n> > +\t\t\t\t\t  minFrameDurations);\n> > +\t}\n> > +\n> > +\tuint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY;\n> > +\tstaticMetadata_->addEntry(ANDROID_SCALER_CROPPING_TYPE, croppingType);\n> > +\n> > +\t/* Info static metadata. */\n> > +\tuint8_t supportedHWLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;\n> > +\tstaticMetadata_->addEntry(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,\n> > +\t\t\t\t  supportedHWLevel);\n> > +\n> > +\t/* Request static metadata. */\n> > +\tint32_t partialResultCount = 1;\n> > +\tstaticMetadata_->addEntry(ANDROID_REQUEST_PARTIAL_RESULT_COUNT,\n> > +\t\t\t\t  partialResultCount);\n> > +\n> > +\t{\n> > +\t\t/* Default the value to 2 if not reported by the camera. */\n> > +\t\tuint8_t maxPipelineDepth = 2;\n> > +\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::PipelineDepth);\n> > +\t\tif (infoMap != controlsInfo.end())\n> > +\t\t\tmaxPipelineDepth = infoMap->second.max().get<int32_t>();\n> > +\t\tstaticMetadata_->addEntry(ANDROID_REQUEST_PIPELINE_MAX_DEPTH,\n> > +\t\t\t\t\t  maxPipelineDepth);\n> > +\t}\n> > +\n> > +\t/* LIMITED does not support reprocessing. */\n> > +\tuint32_t maxNumInputStreams = 0;\n> > +\tstaticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,\n> > +\t\t\t\t  maxNumInputStreams);\n> > +\n> > +\tstd::vector<uint8_t> availableCapabilities = {\n> > +\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,\n> > +\t};\n> > +\n> > +\t/* Report if camera supports RAW. */\n> > +\tbool rawStreamAvailable = false;\n> > +\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> > +\t\tcamera_->generateConfiguration({ StreamRole::Raw });\n> > +\tif (cameraConfig && !cameraConfig->empty()) {\n> > +\t\tconst PixelFormatInfo &info =\n> > +\t\t\tPixelFormatInfo::info(cameraConfig->at(0).pixelFormat);\n> > +\t\t/* Only advertise RAW support if RAW16 is possible. */\n> > +\t\tif (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW &&\n> > +\t\t    info.bitsPerPixel == 16) {\n> > +\t\t\trawStreamAvailable = true;\n> > +\t\t\tavailableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);\n> > +\t\t}\n> > +\t}\n> > +\n> > +\t/* Number of { RAW, YUV, JPEG } supported output streams */\n> > +\tint32_t numOutStreams[] = { rawStreamAvailable, 2, 1 };\n> > +\tstaticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,\n> > +\t\t\t\t  numOutStreams);\n> > +\n> > +\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CAPABILITIES,\n> > +\t\t\t\t  availableCapabilities);\n> > +\n> > +\tstd::vector<int32_t> availableCharacteristicsKeys = {\n> > +\t\tANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,\n> > +\t\tANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,\n> > +\t\tANDROID_CONTROL_AE_AVAILABLE_MODES,\n> > +\t\tANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> > +\t\tANDROID_CONTROL_AE_COMPENSATION_RANGE,\n> > +\t\tANDROID_CONTROL_AE_COMPENSATION_STEP,\n> > +\t\tANDROID_CONTROL_AE_LOCK_AVAILABLE,\n> > +\t\tANDROID_CONTROL_AF_AVAILABLE_MODES,\n> > +\t\tANDROID_CONTROL_AVAILABLE_EFFECTS,\n> > +\t\tANDROID_CONTROL_AVAILABLE_MODES,\n> > +\t\tANDROID_CONTROL_AVAILABLE_SCENE_MODES,\n> > +\t\tANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,\n> > +\t\tANDROID_CONTROL_AWB_AVAILABLE_MODES,\n> > +\t\tANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> > +\t\tANDROID_CONTROL_MAX_REGIONS,\n> > +\t\tANDROID_CONTROL_SCENE_MODE_OVERRIDES,\n> > +\t\tANDROID_FLASH_INFO_AVAILABLE,\n> > +\t\tANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,\n> > +\t\tANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,\n> > +\t\tANDROID_JPEG_MAX_SIZE,\n> > +\t\tANDROID_LENS_FACING,\n> > +\t\tANDROID_LENS_INFO_AVAILABLE_APERTURES,\n> > +\t\tANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,\n> > +\t\tANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,\n> > +\t\tANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,\n> > +\t\tANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,\n> > +\t\tANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,\n> > +\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES,\n> > +\t\tANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,\n> > +\t\tANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,\n> > +\t\tANDROID_REQUEST_PARTIAL_RESULT_COUNT,\n> > +\t\tANDROID_REQUEST_PIPELINE_MAX_DEPTH,\n> > +\t\tANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,\n> > +\t\tANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,\n> > +\t\tANDROID_SCALER_AVAILABLE_STALL_DURATIONS,\n> > +\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,\n> > +\t\tANDROID_SCALER_CROPPING_TYPE,\n> > +\t\tANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,\n> > +\t\tANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,\n> > +\t\tANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,\n> > +\t\tANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,\n> > +\t\tANDROID_SENSOR_INFO_MAX_FRAME_DURATION,\n> > +\t\tANDROID_SENSOR_INFO_PHYSICAL_SIZE,\n> > +\t\tANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,\n> > +\t\tANDROID_SENSOR_INFO_SENSITIVITY_RANGE,\n> > +\t\tANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,\n> > +\t\tANDROID_SENSOR_ORIENTATION,\n> > +\t\tANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,\n> > +\t\tANDROID_STATISTICS_INFO_MAX_FACE_COUNT,\n> > +\t\tANDROID_SYNC_MAX_LATENCY,\n> > +\t};\n> > +\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,\n> > +\t\t\t\t  availableCharacteristicsKeys);\n> > +\n> > +\tstd::vector<int32_t> availableRequestKeys = {\n> > +\t\tANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> > +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> > +\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> > +\t\tANDROID_CONTROL_AE_LOCK,\n> > +\t\tANDROID_CONTROL_AE_MODE,\n> > +\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> > +\t\tANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> > +\t\tANDROID_CONTROL_AF_MODE,\n> > +\t\tANDROID_CONTROL_AF_TRIGGER,\n> > +\t\tANDROID_CONTROL_AWB_LOCK,\n> > +\t\tANDROID_CONTROL_AWB_MODE,\n> > +\t\tANDROID_CONTROL_CAPTURE_INTENT,\n> > +\t\tANDROID_CONTROL_EFFECT_MODE,\n> > +\t\tANDROID_CONTROL_MODE,\n> > +\t\tANDROID_CONTROL_SCENE_MODE,\n> > +\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE,\n> > +\t\tANDROID_FLASH_MODE,\n> > +\t\tANDROID_JPEG_ORIENTATION,\n> > +\t\tANDROID_JPEG_QUALITY,\n> > +\t\tANDROID_JPEG_THUMBNAIL_QUALITY,\n> > +\t\tANDROID_JPEG_THUMBNAIL_SIZE,\n> > +\t\tANDROID_LENS_APERTURE,\n> > +\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> > +\t\tANDROID_NOISE_REDUCTION_MODE,\n> > +\t\tANDROID_SCALER_CROP_REGION,\n> > +\t\tANDROID_STATISTICS_FACE_DETECT_MODE\n> > +\t};\n> > +\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,\n> > +\t\t\t\t  availableRequestKeys);\n> > +\n> > +\tstd::vector<int32_t> availableResultKeys = {\n> > +\t\tANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> > +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> > +\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> > +\t\tANDROID_CONTROL_AE_LOCK,\n> > +\t\tANDROID_CONTROL_AE_MODE,\n> > +\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> > +\t\tANDROID_CONTROL_AE_STATE,\n> > +\t\tANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> > +\t\tANDROID_CONTROL_AF_MODE,\n> > +\t\tANDROID_CONTROL_AF_STATE,\n> > +\t\tANDROID_CONTROL_AF_TRIGGER,\n> > +\t\tANDROID_CONTROL_AWB_LOCK,\n> > +\t\tANDROID_CONTROL_AWB_MODE,\n> > +\t\tANDROID_CONTROL_AWB_STATE,\n> > +\t\tANDROID_CONTROL_CAPTURE_INTENT,\n> > +\t\tANDROID_CONTROL_EFFECT_MODE,\n> > +\t\tANDROID_CONTROL_MODE,\n> > +\t\tANDROID_CONTROL_SCENE_MODE,\n> > +\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE,\n> > +\t\tANDROID_FLASH_MODE,\n> > +\t\tANDROID_FLASH_STATE,\n> > +\t\tANDROID_JPEG_GPS_COORDINATES,\n> > +\t\tANDROID_JPEG_GPS_PROCESSING_METHOD,\n> > +\t\tANDROID_JPEG_GPS_TIMESTAMP,\n> > +\t\tANDROID_JPEG_ORIENTATION,\n> > +\t\tANDROID_JPEG_QUALITY,\n> > +\t\tANDROID_JPEG_SIZE,\n> > +\t\tANDROID_JPEG_THUMBNAIL_QUALITY,\n> > +\t\tANDROID_JPEG_THUMBNAIL_SIZE,\n> > +\t\tANDROID_LENS_APERTURE,\n> > +\t\tANDROID_LENS_FOCAL_LENGTH,\n> > +\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> > +\t\tANDROID_LENS_STATE,\n> > +\t\tANDROID_NOISE_REDUCTION_MODE,\n> > +\t\tANDROID_REQUEST_PIPELINE_DEPTH,\n> > +\t\tANDROID_SCALER_CROP_REGION,\n> > +\t\tANDROID_SENSOR_EXPOSURE_TIME,\n> > +\t\tANDROID_SENSOR_FRAME_DURATION,\n> > +\t\tANDROID_SENSOR_ROLLING_SHUTTER_SKEW,\n> > +\t\tANDROID_SENSOR_TEST_PATTERN_MODE,\n> > +\t\tANDROID_SENSOR_TIMESTAMP,\n> > +\t\tANDROID_STATISTICS_FACE_DETECT_MODE,\n> > +\t\tANDROID_STATISTICS_LENS_SHADING_MAP_MODE,\n> > +\t\tANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,\n> > +\t\tANDROID_STATISTICS_SCENE_FLICKER,\n> > +\t};\n> > +\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,\n> > +\t\t\t\t  availableResultKeys);\n> > +\n> > +\tif (!staticMetadata_->isValid()) {\n> > +\t\tLOG(HAL, Error) << \"Failed to construct static metadata\";\n> > +\t\tstaticMetadata_.reset();\n> > +\t\treturn -EINVAL;\n> > +\t}\n> > +\n> > +\tif (staticMetadata_->resized()) {\n> > +\t\tauto [entryCount, dataCount] = staticMetadata_->usage();\n> > +\t\tLOG(HAL, Info)\n> > +\t\t\t<< \"Static metadata resized: \" << entryCount\n> > +\t\t\t<< \" entries and \" << dataCount << \" bytes used\";\n> > +\t}\n> > +\n> > +\treturn 0;\n> > +}\n> > +\n> > +/* Translate Android format code to libcamera pixel format. */\n> > +PixelFormat CameraCapabilities::toPixelFormat(int format) const\n> > +{\n> > +\tauto it = formatsMap_.find(format);\n> > +\tif (it == formatsMap_.end()) {\n> > +\t\tLOG(HAL, Error) << \"Requested format \" << utils::hex(format)\n> > +\t\t\t\t<< \" not supported\";\n> > +\t\treturn PixelFormat();\n> > +\t}\n> > +\n> > +\treturn it->second;\n> > +}\n> > +\n> > +std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplatePreview() const\n> > +{\n> > +\t/*\n> > +\t * \\todo Keep this in sync with the actual number of entries.\n> > +\t * Currently: 20 entries, 35 bytes\n> > +\t */\n> > +\tauto requestTemplate = std::make_unique<CameraMetadata>(21, 36);\n> > +\tif (!requestTemplate->isValid()) {\n> > +\t\treturn nullptr;\n> > +\t}\n> > +\n> > +\t/* Get the FPS range registered in the static metadata. */\n> > +\tcamera_metadata_ro_entry_t entry;\n> > +\tbool found = staticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> > +\t\t\t\t\t       &entry);\n> > +\tif (!found) {\n> > +\t\tLOG(HAL, Error) << \"Cannot create capture template without FPS range\";\n> > +\t\treturn nullptr;\n> > +\t}\n> > +\n> > +\t/*\n> > +\t * Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata\n> > +\t * has been assembled as {{min, max} {max, max}}.\n> > +\t */\n> > +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> > +\t\t\t\t  entry.data.i32, 2);\n> > +\n> > +\tuint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;\n> > +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_MODE, aeMode);\n> > +\n> > +\tint32_t aeExposureCompensation = 0;\n> > +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> > +\t\t\t\t  aeExposureCompensation);\n> > +\n> > +\tuint8_t aePrecaptureTrigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;\n> > +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> > +\t\t\t\t  aePrecaptureTrigger);\n> > +\n> > +\tuint8_t aeLock = ANDROID_CONTROL_AE_LOCK_OFF;\n> > +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_LOCK, aeLock);\n> > +\n> > +\tuint8_t aeAntibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;\n> > +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> > +\t\t\t\t  aeAntibandingMode);\n> > +\n> > +\tuint8_t afMode = ANDROID_CONTROL_AF_MODE_OFF;\n> > +\trequestTemplate->addEntry(ANDROID_CONTROL_AF_MODE, afMode);\n> > +\n> > +\tuint8_t afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;\n> > +\trequestTemplate->addEntry(ANDROID_CONTROL_AF_TRIGGER, afTrigger);\n> > +\n> > +\tuint8_t awbMode = ANDROID_CONTROL_AWB_MODE_AUTO;\n> > +\trequestTemplate->addEntry(ANDROID_CONTROL_AWB_MODE, awbMode);\n> > +\n> > +\tuint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;\n> > +\trequestTemplate->addEntry(ANDROID_CONTROL_AWB_LOCK, awbLock);\n> > +\n> > +\tuint8_t flashMode = ANDROID_FLASH_MODE_OFF;\n> > +\trequestTemplate->addEntry(ANDROID_FLASH_MODE, flashMode);\n> > +\n> > +\tuint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;\n> > +\trequestTemplate->addEntry(ANDROID_STATISTICS_FACE_DETECT_MODE,\n> > +\t\t\t\t  faceDetectMode);\n> > +\n> > +\tuint8_t noiseReduction = ANDROID_NOISE_REDUCTION_MODE_OFF;\n> > +\trequestTemplate->addEntry(ANDROID_NOISE_REDUCTION_MODE,\n> > +\t\t\t\t  noiseReduction);\n> > +\n> > +\tuint8_t aberrationMode = ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF;\n> > +\trequestTemplate->addEntry(ANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> > +\t\t\t\t  aberrationMode);\n> > +\n> > +\tuint8_t controlMode = ANDROID_CONTROL_MODE_AUTO;\n> > +\trequestTemplate->addEntry(ANDROID_CONTROL_MODE, controlMode);\n> > +\n> > +\tfloat lensAperture = 2.53 / 100;\n> > +\trequestTemplate->addEntry(ANDROID_LENS_APERTURE, lensAperture);\n> > +\n> > +\tuint8_t opticalStabilization = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;\n> > +\trequestTemplate->addEntry(ANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> > +\t\t\t\t  opticalStabilization);\n> > +\n> > +\tuint8_t captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;\n> > +\trequestTemplate->addEntry(ANDROID_CONTROL_CAPTURE_INTENT,\n> > +\t\t\t\t  captureIntent);\n> > +\n> > +\treturn requestTemplate;\n> > +}\n> > +\n> > +std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplateVideo() const\n> > +{\n> > +\tstd::unique_ptr<CameraMetadata> previewTemplate = requestTemplatePreview();\n> > +\tif (!previewTemplate)\n> > +\t\treturn nullptr;\n> > +\n> > +\t/*\n> > +\t * The video template requires a fixed FPS range. Everything else\n> > +\t * stays the same as the preview template.\n> > +\t */\n> > +\tcamera_metadata_ro_entry_t entry;\n> > +\tstaticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> > +\t\t\t\t  &entry);\n> > +\n> > +\t/*\n> > +\t * Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata\n> > +\t * has been assembled as {{min, max} {max, max}}.\n> > +\t */\n> > +\tpreviewTemplate->updateEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> > +\t\t\t\t     entry.data.i32 + 2, 2);\n> > +\n> > +\treturn previewTemplate;\n> > +}\n> > diff --git a/src/android/camera_capabilities.h b/src/android/camera_capabilities.h\n> > new file mode 100644\n> > index 000000000000..3a427e768aff\n> > --- /dev/null\n> > +++ b/src/android/camera_capabilities.h\n> > @@ -0,0 +1,64 @@\n> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > +/*\n> > + * Copyright (C) 2021, Google Inc.\n> > + *\n> > + * camera_capabilities.h - Camera static properties manager\n> > + */\n> > +#ifndef __ANDROID_CAMERA_CAPABILITIES_H__\n> > +#define __ANDROID_CAMERA_CAPABILITIES_H__\n> > +\n> > +#include <map>\n> > +#include <memory>\n> > +#include <vector>\n> > +\n> > +#include <libcamera/camera.h>\n> > +#include <libcamera/class.h>\n> > +#include <libcamera/geometry.h>\n> > +\n> > +#include \"camera_metadata.h\"\n> > +\n> > +class CameraCapabilities\n> > +{\n> > +public:\n> > +\tCameraCapabilities() = default;\n> > +\n> > +\tint initialize(std::shared_ptr<libcamera::Camera> camera,\n> > +\t\t       int orientation, int facing);\n> > +\n> > +\tCameraMetadata *staticMetadata() const { return staticMetadata_.get(); }\n> > +\tlibcamera::PixelFormat toPixelFormat(int format) const;\n>\n> You should include libcamera/format.h for PixelFormat.\n\nack!\n\n>\n> > +\tunsigned int maxJpegBufferSize() const { return maxJpegBufferSize_; }\n> > +\n> > +\tstd::unique_ptr<CameraMetadata> requestTemplatePreview() const;\n> > +\tstd::unique_ptr<CameraMetadata> requestTemplateVideo() const;\n> > +\n> > +private:\n> > +\tLIBCAMERA_DISABLE_COPY_AND_MOVE(CameraCapabilities)\n> > +\n> > +\tstruct Camera3StreamConfiguration {\n> > +\t\tlibcamera::Size resolution;\n> > +\t\tint androidFormat;\n> > +\t};\n> > +\n> > +\tstd::vector<libcamera::Size>\n> > +\tgetYUVResolutions(libcamera::CameraConfiguration *cameraConfig,\n>\n> This needs libcamera/camera.h.\n>\nIsn't it included ?\n\n> > +#include <libcamera/camera.h>\n\n> > +\t\t\t  const libcamera::PixelFormat &pixelFormat,\n> > +\t\t\t  const std::vector<libcamera::Size> &resolutions);\n> > +\tstd::vector<libcamera::Size>\n> > +\tgetRawResolutions(const libcamera::PixelFormat &pixelFormat);\n> > +\tint initializeStreamConfigurations();\n> > +\n> > +\tint initializeStaticMetadata();\n> > +\n> > +\tstd::shared_ptr<libcamera::Camera> camera_;\n> > +\n> > +\tint facing_;\n> > +\tint orientation_;\n> > +\n> > +\tstd::vector<Camera3StreamConfiguration> streamConfigurations_;\n> > +\tstd::map<int, libcamera::PixelFormat> formatsMap_;\n> > +\tstd::unique_ptr<CameraMetadata> staticMetadata_;\n> > +\tunsigned int maxJpegBufferSize_;\n> > +};\n> > +\n> > +#endif /* __ANDROID_CAMERA_CAPABILITIES_H__ */\n> > diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp\n> > index 8c71fd0675d3..4bd125d7020a 100644\n> > --- a/src/android/camera_device.cpp\n> > +++ b/src/android/camera_device.cpp\n> > @@ -10,11 +10,8 @@\n> >  #include \"camera_ops.h\"\n> >  #include \"post_processor.h\"\n> >\n> > -#include <array>\n> > -#include <cmath>\n> >  #include <fstream>\n> >  #include <sys/mman.h>\n> > -#include <tuple>\n> >  #include <unistd.h>\n> >  #include <vector>\n> >\n> > @@ -23,7 +20,6 @@\n> >  #include <libcamera/formats.h>\n> >  #include <libcamera/property_ids.h>\n> >\n> > -#include \"libcamera/internal/formats.h\"\n> >  #include \"libcamera/internal/log.h\"\n> >  #include \"libcamera/internal/thread.h\"\n> >  #include \"libcamera/internal/utils.h\"\n> > @@ -36,94 +32,6 @@ LOG_DECLARE_CATEGORY(HAL)\n> >\n> >  namespace {\n> >\n> > -/*\n> > - * \\var camera3Resolutions\n> > - * \\brief The list of image resolutions defined as mandatory to be supported by\n> > - * the Android Camera3 specification\n> > - */\n> > -const std::vector<Size> camera3Resolutions = {\n> > -\t{ 320, 240 },\n> > -\t{ 640, 480 },\n> > -\t{ 1280, 720 },\n> > -\t{ 1920, 1080 }\n> > -};\n> > -\n> > -/*\n> > - * \\struct Camera3Format\n> > - * \\brief Data associated with an Android format identifier\n> > - * \\var libcameraFormats List of libcamera pixel formats compatible with the\n> > - * Android format\n> > - * \\var name The human-readable representation of the Android format code\n> > - */\n> > -struct Camera3Format {\n> > -\tstd::vector<PixelFormat> libcameraFormats;\n> > -\tbool mandatory;\n> > -\tconst char *name;\n> > -};\n> > -\n> > -/*\n> > - * \\var camera3FormatsMap\n> > - * \\brief Associate Android format code with ancillary data\n> > - */\n> > -const std::map<int, const Camera3Format> camera3FormatsMap = {\n> > -\t{\n> > -\t\tHAL_PIXEL_FORMAT_BLOB, {\n> > -\t\t\t{ formats::MJPEG },\n> > -\t\t\ttrue,\n> > -\t\t\t\"BLOB\"\n> > -\t\t}\n> > -\t}, {\n> > -\t\tHAL_PIXEL_FORMAT_YCbCr_420_888, {\n> > -\t\t\t{ formats::NV12, formats::NV21 },\n> > -\t\t\ttrue,\n> > -\t\t\t\"YCbCr_420_888\"\n> > -\t\t}\n> > -\t}, {\n> > -\t\t/*\n> > -\t\t * \\todo Translate IMPLEMENTATION_DEFINED inspecting the gralloc\n> > -\t\t * usage flag. For now, copy the YCbCr_420 configuration.\n> > -\t\t */\n> > -\t\tHAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, {\n> > -\t\t\t{ formats::NV12, formats::NV21 },\n> > -\t\t\ttrue,\n> > -\t\t\t\"IMPLEMENTATION_DEFINED\"\n> > -\t\t}\n> > -\t}, {\n> > -\t\tHAL_PIXEL_FORMAT_RAW10, {\n> > -\t\t\t{\n> > -\t\t\t\tformats::SBGGR10_CSI2P,\n> > -\t\t\t\tformats::SGBRG10_CSI2P,\n> > -\t\t\t\tformats::SGRBG10_CSI2P,\n> > -\t\t\t\tformats::SRGGB10_CSI2P\n> > -\t\t\t},\n> > -\t\t\tfalse,\n> > -\t\t\t\"RAW10\"\n> > -\t\t}\n> > -\t}, {\n> > -\t\tHAL_PIXEL_FORMAT_RAW12, {\n> > -\t\t\t{\n> > -\t\t\t\tformats::SBGGR12_CSI2P,\n> > -\t\t\t\tformats::SGBRG12_CSI2P,\n> > -\t\t\t\tformats::SGRBG12_CSI2P,\n> > -\t\t\t\tformats::SRGGB12_CSI2P\n> > -\t\t\t},\n> > -\t\t\tfalse,\n> > -\t\t\t\"RAW12\"\n> > -\t\t}\n> > -\t}, {\n> > -\t\tHAL_PIXEL_FORMAT_RAW16, {\n> > -\t\t\t{\n> > -\t\t\t\tformats::SBGGR16,\n> > -\t\t\t\tformats::SGBRG16,\n> > -\t\t\t\tformats::SGRBG16,\n> > -\t\t\t\tformats::SRGGB16\n> > -\t\t\t},\n> > -\t\t\tfalse,\n> > -\t\t\t\"RAW16\"\n> > -\t\t}\n> > -\t},\n> > -};\n> > -\n> >  /*\n> >   * \\struct Camera3StreamConfig\n> >   * \\brief Data to store StreamConfiguration associated with camera3_stream(s)\n> > @@ -512,242 +420,7 @@ int CameraDevice::initialize(const CameraConfigData *cameraConfigData)\n> >  \t\torientation_ = 0;\n> >  \t}\n>\n> Shouldn't the code above be moved too ?\n>\n\nIt seems to me it deals with run time stream configuration, not to\nbuilding the static list of available camera streams like the part I\nmoved, doesn't it ?\n\n> >\n> > -\t/* Acquire the camera and initialize available stream configurations. */\n> > -\tint ret = camera_->acquire();\n> > -\tif (ret) {\n> > -\t\tLOG(HAL, Error) << \"Failed to temporarily acquire the camera\";\n> > -\t\treturn ret;\n> > -\t}\n> > -\n> > -\tret = initializeStreamConfigurations();\n> > -\tcamera_->release();\n> > -\treturn ret;\n> > -}\n> > -\n> > -std::vector<Size> CameraDevice::getYUVResolutions(CameraConfiguration *cameraConfig,\n> > -\t\t\t\t\t\t  const PixelFormat &pixelFormat,\n> > -\t\t\t\t\t\t  const std::vector<Size> &resolutions)\n> > -{\n> > -\tstd::vector<Size> supportedResolutions;\n> > -\n> > -\tStreamConfiguration &cfg = cameraConfig->at(0);\n> > -\tfor (const Size &res : resolutions) {\n> > -\t\tcfg.pixelFormat = pixelFormat;\n> > -\t\tcfg.size = res;\n> > -\n> > -\t\tCameraConfiguration::Status status = cameraConfig->validate();\n> > -\t\tif (status != CameraConfiguration::Valid) {\n> > -\t\t\tLOG(HAL, Debug) << cfg.toString() << \" not supported\";\n> > -\t\t\tcontinue;\n> > -\t\t}\n> > -\n> > -\t\tLOG(HAL, Debug) << cfg.toString() << \" supported\";\n> > -\n> > -\t\tsupportedResolutions.push_back(res);\n> > -\t}\n> > -\n> > -\treturn supportedResolutions;\n> > -}\n> > -\n> > -std::vector<Size> CameraDevice::getRawResolutions(const libcamera::PixelFormat &pixelFormat)\n> > -{\n> > -\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> > -\t\tcamera_->generateConfiguration({ StreamRole::Raw });\n> > -\tStreamConfiguration &cfg = cameraConfig->at(0);\n> > -\tconst StreamFormats &formats = cfg.formats();\n> > -\tstd::vector<Size> supportedResolutions = formats.sizes(pixelFormat);\n> > -\n> > -\treturn supportedResolutions;\n> > -}\n> > -\n> > -/*\n> > - * Initialize the format conversion map to translate from Android format\n> > - * identifier to libcamera pixel formats and fill in the list of supported\n> > - * stream configurations to be reported to the Android camera framework through\n> > - * the static stream configuration metadata.\n> > - */\n> > -int CameraDevice::initializeStreamConfigurations()\n> > -{\n> > -\t/*\n> > -\t * Get the maximum output resolutions\n> > -\t * \\todo Get this from the camera properties once defined\n> > -\t */\n> > -\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> > -\t\tcamera_->generateConfiguration({ StillCapture });\n> > -\tif (!cameraConfig) {\n> > -\t\tLOG(HAL, Error) << \"Failed to get maximum resolution\";\n> > -\t\treturn -EINVAL;\n> > -\t}\n> > -\tStreamConfiguration &cfg = cameraConfig->at(0);\n> > -\n> > -\t/*\n> > -\t * \\todo JPEG - Adjust the maximum available resolution by taking the\n> > -\t * JPEG encoder requirements into account (alignment and aspect ratio).\n> > -\t */\n> > -\tconst Size maxRes = cfg.size;\n> > -\tLOG(HAL, Debug) << \"Maximum supported resolution: \" << maxRes.toString();\n> > -\n> > -\t/*\n> > -\t * Build the list of supported image resolutions.\n> > -\t *\n> > -\t * The resolutions listed in camera3Resolution are mandatory to be\n> > -\t * supported, up to the camera maximum resolution.\n> > -\t *\n> > -\t * Augment the list by adding resolutions calculated from the camera\n> > -\t * maximum one.\n> > -\t */\n> > -\tstd::vector<Size> cameraResolutions;\n> > -\tstd::copy_if(camera3Resolutions.begin(), camera3Resolutions.end(),\n> > -\t\t     std::back_inserter(cameraResolutions),\n> > -\t\t     [&](const Size &res) { return res < maxRes; });\n> > -\n> > -\t/*\n> > -\t * The Camera3 specification suggests adding 1/2 and 1/4 of the maximum\n> > -\t * resolution.\n> > -\t */\n> > -\tfor (unsigned int divider = 2;; divider <<= 1) {\n> > -\t\tSize derivedSize{\n> > -\t\t\tmaxRes.width / divider,\n> > -\t\t\tmaxRes.height / divider,\n> > -\t\t};\n> > -\n> > -\t\tif (derivedSize.width < 320 ||\n> > -\t\t    derivedSize.height < 240)\n> > -\t\t\tbreak;\n> > -\n> > -\t\tcameraResolutions.push_back(derivedSize);\n> > -\t}\n> > -\tcameraResolutions.push_back(maxRes);\n> > -\n> > -\t/* Remove duplicated entries from the list of supported resolutions. */\n> > -\tstd::sort(cameraResolutions.begin(), cameraResolutions.end());\n> > -\tauto last = std::unique(cameraResolutions.begin(), cameraResolutions.end());\n> > -\tcameraResolutions.erase(last, cameraResolutions.end());\n> > -\n> > -\t/*\n> > -\t * Build the list of supported camera formats.\n> > -\t *\n> > -\t * To each Android format a list of compatible libcamera formats is\n> > -\t * associated. The first libcamera format that tests successful is added\n> > -\t * to the format translation map used when configuring the streams.\n> > -\t * It is then tested against the list of supported camera resolutions to\n> > -\t * build the stream configuration map reported through the camera static\n> > -\t * metadata.\n> > -\t */\n> > -\tSize maxJpegSize;\n> > -\tfor (const auto &format : camera3FormatsMap) {\n> > -\t\tint androidFormat = format.first;\n> > -\t\tconst Camera3Format &camera3Format = format.second;\n> > -\t\tconst std::vector<PixelFormat> &libcameraFormats =\n> > -\t\t\tcamera3Format.libcameraFormats;\n> > -\n> > -\t\tLOG(HAL, Debug) << \"Trying to map Android format \"\n> > -\t\t\t\t<< camera3Format.name;\n> > -\n> > -\t\t/*\n> > -\t\t * JPEG is always supported, either produced directly by the\n> > -\t\t * camera, or encoded in the HAL.\n> > -\t\t */\n> > -\t\tif (androidFormat == HAL_PIXEL_FORMAT_BLOB) {\n> > -\t\t\tformatsMap_[androidFormat] = formats::MJPEG;\n> > -\t\t\tLOG(HAL, Debug) << \"Mapped Android format \"\n> > -\t\t\t\t\t<< camera3Format.name << \" to \"\n> > -\t\t\t\t\t<< formats::MJPEG.toString()\n> > -\t\t\t\t\t<< \" (fixed mapping)\";\n> > -\t\t\tcontinue;\n> > -\t\t}\n> > -\n> > -\t\t/*\n> > -\t\t * Test the libcamera formats that can produce images\n> > -\t\t * compatible with the format defined by Android.\n> > -\t\t */\n> > -\t\tPixelFormat mappedFormat;\n> > -\t\tfor (const PixelFormat &pixelFormat : libcameraFormats) {\n> > -\n> > -\t\t\tLOG(HAL, Debug) << \"Testing \" << pixelFormat.toString();\n> > -\n> > -\t\t\t/*\n> > -\t\t\t * The stream configuration size can be adjusted,\n> > -\t\t\t * not the pixel format.\n> > -\t\t\t *\n> > -\t\t\t * \\todo This could be simplified once all pipeline\n> > -\t\t\t * handlers will report the StreamFormats list of\n> > -\t\t\t * supported formats.\n> > -\t\t\t */\n> > -\t\t\tcfg.pixelFormat = pixelFormat;\n> > -\n> > -\t\t\tCameraConfiguration::Status status = cameraConfig->validate();\n> > -\t\t\tif (status != CameraConfiguration::Invalid &&\n> > -\t\t\t    cfg.pixelFormat == pixelFormat) {\n> > -\t\t\t\tmappedFormat = pixelFormat;\n> > -\t\t\t\tbreak;\n> > -\t\t\t}\n> > -\t\t}\n> > -\n> > -\t\tif (!mappedFormat.isValid()) {\n> > -\t\t\t/* If the format is not mandatory, skip it. */\n> > -\t\t\tif (!camera3Format.mandatory)\n> > -\t\t\t\tcontinue;\n> > -\n> > -\t\t\tLOG(HAL, Error)\n> > -\t\t\t\t<< \"Failed to map mandatory Android format \"\n> > -\t\t\t\t<< camera3Format.name << \" (\"\n> > -\t\t\t\t<< utils::hex(androidFormat) << \"): aborting\";\n> > -\t\t\treturn -EINVAL;\n> > -\t\t}\n> > -\n> > -\t\t/*\n> > -\t\t * Record the mapping and then proceed to generate the\n> > -\t\t * stream configurations map, by testing the image resolutions.\n> > -\t\t */\n> > -\t\tformatsMap_[androidFormat] = mappedFormat;\n> > -\t\tLOG(HAL, Debug) << \"Mapped Android format \"\n> > -\t\t\t\t<< camera3Format.name << \" to \"\n> > -\t\t\t\t<< mappedFormat.toString();\n> > -\n> > -\t\tstd::vector<Size> resolutions;\n> > -\t\tconst PixelFormatInfo &info = PixelFormatInfo::info(mappedFormat);\n> > -\t\tif (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW)\n> > -\t\t\tresolutions = getRawResolutions(mappedFormat);\n> > -\t\telse\n> > -\t\t\tresolutions = getYUVResolutions(cameraConfig.get(),\n> > -\t\t\t\t\t\t\tmappedFormat,\n> > -\t\t\t\t\t\t\tcameraResolutions);\n> > -\n> > -\t\tfor (const Size &res : resolutions) {\n> > -\t\t\tstreamConfigurations_.push_back({ res, androidFormat });\n> > -\n> > -\t\t\t/*\n> > -\t\t\t * If the format is HAL_PIXEL_FORMAT_YCbCr_420_888\n> > -\t\t\t * from which JPEG is produced, add an entry for\n> > -\t\t\t * the JPEG stream.\n> > -\t\t\t *\n> > -\t\t\t * \\todo Wire the JPEG encoder to query the supported\n> > -\t\t\t * sizes provided a list of formats it can encode.\n> > -\t\t\t *\n> > -\t\t\t * \\todo Support JPEG streams produced by the Camera\n> > -\t\t\t * natively.\n> > -\t\t\t */\n> > -\t\t\tif (androidFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {\n> > -\t\t\t\tstreamConfigurations_.push_back(\n> > -\t\t\t\t\t{ res, HAL_PIXEL_FORMAT_BLOB });\n> > -\t\t\t\tmaxJpegSize = std::max(maxJpegSize, res);\n> > -\t\t\t}\n> > -\t\t}\n> > -\n> > -\t\t/*\n> > -\t\t * \\todo Calculate the maximum JPEG buffer size by asking the\n> > -\t\t * encoder giving the maximum frame size required.\n> > -\t\t */\n> > -\t\tmaxJpegBufferSize_ = maxJpegSize.width * maxJpegSize.height * 1.5;\n> > -\t}\n> > -\n> > -\tLOG(HAL, Debug) << \"Collected stream configuration map: \";\n> > -\tfor (const auto &entry : streamConfigurations_)\n> > -\t\tLOG(HAL, Debug) << \"{ \" << entry.resolution.toString() << \" - \"\n> > -\t\t\t\t<< utils::hex(entry.androidFormat) << \" }\";\n> > -\n> > -\treturn 0;\n> > +\treturn capabilities_.initialize(camera_, orientation_, facing_);\n> >  }\n> >\n> >  /*\n> > @@ -817,802 +490,19 @@ void CameraDevice::stop()\n> >  \tstate_ = State::Stopped;\n> >  }\n> >\n> > -void CameraDevice::setCallbacks(const camera3_callback_ops_t *callbacks)\n> > +unsigned int CameraDevice::maxJpegBufferSize() const\n> >  {\n> > -\tcallbacks_ = callbacks;\n> > +\treturn capabilities_.maxJpegBufferSize();\n> >  }\n> >\n> > -/*\n> > - * Return static information for the camera.\n> > - */\n> > -const camera_metadata_t *CameraDevice::getStaticMetadata()\n> > -{\n> > -\tif (staticMetadata_)\n> > -\t\treturn staticMetadata_->get();\n> > -\n> > -\tstaticMetadata_ = std::make_unique<CameraMetadata>(64, 1024);\n> > -\tif (!staticMetadata_->isValid()) {\n> > -\t\tLOG(HAL, Error) << \"Failed to allocate static metadata\";\n> > -\t\tstaticMetadata_.reset();\n> > -\t\treturn nullptr;\n> > -\t}\n> > -\n> > -\tconst ControlInfoMap &controlsInfo = camera_->controls();\n> > -\tconst ControlList &properties = camera_->properties();\n> > -\n> > -\t/* Color correction static metadata. */\n> > -\t{\n> > -\t\tstd::vector<uint8_t> data;\n> > -\t\tdata.reserve(3);\n> > -\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::ColorCorrectionAberrationMode);\n> > -\t\tif (infoMap != controlsInfo.end()) {\n> > -\t\t\tfor (const auto &value : infoMap->second.values())\n> > -\t\t\t\tdata.push_back(value.get<int32_t>());\n> > -\t\t} else {\n> > -\t\t\tdata.push_back(ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF);\n> > -\t\t}\n> > -\t\tstaticMetadata_->addEntry(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,\n> > -\t\t\t\t\t  data);\n> > -\t}\n> > -\n> > -\t/* Control static metadata. */\n> > -\tstd::vector<uint8_t> aeAvailableAntiBandingModes = {\n> > -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF,\n> > -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ,\n> > -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ,\n> > -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO,\n> > -\t};\n> > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,\n> > -\t\t\t\t  aeAvailableAntiBandingModes);\n> > -\n> > -\tstd::vector<uint8_t> aeAvailableModes = {\n> > -\t\tANDROID_CONTROL_AE_MODE_ON,\n> > -\t};\n> > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_MODES,\n> > -\t\t\t\t  aeAvailableModes);\n> > -\n> > -\tint64_t minFrameDurationNsec = -1;\n> > -\tint64_t maxFrameDurationNsec = -1;\n> > -\tconst auto frameDurationsInfo = controlsInfo.find(&controls::FrameDurationLimits);\n> > -\tif (frameDurationsInfo != controlsInfo.end()) {\n> > -\t\tminFrameDurationNsec = frameDurationsInfo->second.min().get<int64_t>() * 1000;\n> > -\t\tmaxFrameDurationNsec = frameDurationsInfo->second.max().get<int64_t>() * 1000;\n> > -\n> > -\t\t/*\n> > -\t\t * Adjust the minimum frame duration to comply with Android\n> > -\t\t * requirements. The camera service mandates all preview/record\n> > -\t\t * streams to have a minimum frame duration < 33,366 milliseconds\n> > -\t\t * (see MAX_PREVIEW_RECORD_DURATION_NS in the camera service\n> > -\t\t * implementation).\n> > -\t\t *\n> > -\t\t * If we're close enough (+ 500 useconds) to that value, round\n> > -\t\t * the minimum frame duration of the camera to an accepted\n> > -\t\t * value.\n> > -\t\t */\n> > -\t\tstatic constexpr int64_t MAX_PREVIEW_RECORD_DURATION_NS = 1e9 / 29.97;\n> > -\t\tif (minFrameDurationNsec > MAX_PREVIEW_RECORD_DURATION_NS &&\n> > -\t\t    minFrameDurationNsec < MAX_PREVIEW_RECORD_DURATION_NS + 500000)\n> > -\t\t\tminFrameDurationNsec = MAX_PREVIEW_RECORD_DURATION_NS - 1000;\n> > -\n> > -\t\t/*\n> > -\t\t * The AE routine frame rate limits are computed using the frame\n> > -\t\t * duration limits, as libcamera clips the AE routine to the\n> > -\t\t * frame durations.\n> > -\t\t */\n> > -\t\tint32_t maxFps = std::round(1e9 / minFrameDurationNsec);\n> > -\t\tint32_t minFps = std::round(1e9 / maxFrameDurationNsec);\n> > -\t\tminFps = std::max(1, minFps);\n> > -\n> > -\t\t/*\n> > -\t\t * Force rounding errors so that we have the proper frame\n> > -\t\t * durations for when we reuse these variables later\n> > -\t\t */\n> > -\t\tminFrameDurationNsec = 1e9 / maxFps;\n> > -\t\tmaxFrameDurationNsec = 1e9 / minFps;\n> > -\n> > -\t\t/*\n> > -\t\t * Register to the camera service {min, max} and {max, max}\n> > -\t\t * intervals as requested by the metadata documentation.\n> > -\t\t */\n> > -\t\tint32_t availableAeFpsTarget[] = {\n> > -\t\t\tminFps, maxFps, maxFps, maxFps\n> > -\t\t};\n> > -\t\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> > -\t\t\t\t\t  availableAeFpsTarget);\n> > -\t}\n> > -\n> > -\tstd::vector<int32_t> aeCompensationRange = {\n> > -\t\t0, 0,\n> > -\t};\n> > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_RANGE,\n> > -\t\t\t\t  aeCompensationRange);\n> > -\n> > -\tconst camera_metadata_rational_t aeCompensationStep[] = {\n> > -\t\t{ 0, 1 }\n> > -\t};\n> > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_STEP,\n> > -\t\t\t\t  aeCompensationStep);\n> > -\n> > -\tstd::vector<uint8_t> availableAfModes = {\n> > -\t\tANDROID_CONTROL_AF_MODE_OFF,\n> > -\t};\n> > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AF_AVAILABLE_MODES,\n> > -\t\t\t\t  availableAfModes);\n> > -\n> > -\tstd::vector<uint8_t> availableEffects = {\n> > -\t\tANDROID_CONTROL_EFFECT_MODE_OFF,\n> > -\t};\n> > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_EFFECTS,\n> > -\t\t\t\t  availableEffects);\n> > -\n> > -\tstd::vector<uint8_t> availableSceneModes = {\n> > -\t\tANDROID_CONTROL_SCENE_MODE_DISABLED,\n> > -\t};\n> > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_SCENE_MODES,\n> > -\t\t\t\t  availableSceneModes);\n> > -\n> > -\tstd::vector<uint8_t> availableStabilizationModes = {\n> > -\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF,\n> > -\t};\n> > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,\n> > -\t\t\t\t  availableStabilizationModes);\n> > -\n> > -\t/*\n> > -\t * \\todo Inspect the Camera capabilities to report the available\n> > -\t * AWB modes. Default to AUTO as CTS tests require it.\n> > -\t */\n> > -\tstd::vector<uint8_t> availableAwbModes = {\n> > -\t\tANDROID_CONTROL_AWB_MODE_AUTO,\n> > -\t};\n> > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AWB_AVAILABLE_MODES,\n> > -\t\t\t\t  availableAwbModes);\n> > -\n> > -\tstd::vector<int32_t> availableMaxRegions = {\n> > -\t\t0, 0, 0,\n> > -\t};\n> > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_MAX_REGIONS,\n> > -\t\t\t\t  availableMaxRegions);\n> > -\n> > -\tstd::vector<uint8_t> sceneModesOverride = {\n> > -\t\tANDROID_CONTROL_AE_MODE_ON,\n> > -\t\tANDROID_CONTROL_AWB_MODE_AUTO,\n> > -\t\tANDROID_CONTROL_AF_MODE_OFF,\n> > -\t};\n> > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_SCENE_MODE_OVERRIDES,\n> > -\t\t\t\t  sceneModesOverride);\n> > -\n> > -\tuint8_t aeLockAvailable = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE;\n> > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE,\n> > -\t\t\t\t  aeLockAvailable);\n> > -\n> > -\tuint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;\n> > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> > -\t\t\t\t  awbLockAvailable);\n> > -\n> > -\tchar availableControlModes = ANDROID_CONTROL_MODE_AUTO;\n> > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_MODES,\n> > -\t\t\t\t  availableControlModes);\n> > -\n> > -\t/* JPEG static metadata. */\n> > -\n> > -\t/*\n> > -\t * Create the list of supported thumbnail sizes by inspecting the\n> > -\t * available JPEG resolutions collected in streamConfigurations_ and\n> > -\t * generate one entry for each aspect ratio.\n> > -\t *\n> > -\t * The JPEG thumbnailer can freely scale, so pick an arbitrary\n> > -\t * (160, 160) size as the bounding rectangle, which is then cropped to\n> > -\t * the different supported aspect ratios.\n> > -\t */\n> > -\tconstexpr Size maxJpegThumbnail(160, 160);\n> > -\tstd::vector<Size> thumbnailSizes;\n> > -\tthumbnailSizes.push_back({ 0, 0 });\n> > -\tfor (const auto &entry : streamConfigurations_) {\n> > -\t\tif (entry.androidFormat != HAL_PIXEL_FORMAT_BLOB)\n> > -\t\t\tcontinue;\n> > -\n> > -\t\tSize thumbnailSize = maxJpegThumbnail\n> > -\t\t\t\t     .boundedToAspectRatio({ entry.resolution.width,\n> > -\t\t\t\t\t\t\t     entry.resolution.height });\n> > -\t\tthumbnailSizes.push_back(thumbnailSize);\n> > -\t}\n> > -\n> > -\tstd::sort(thumbnailSizes.begin(), thumbnailSizes.end());\n> > -\tauto last = std::unique(thumbnailSizes.begin(), thumbnailSizes.end());\n> > -\tthumbnailSizes.erase(last, thumbnailSizes.end());\n> > -\n> > -\t/* Transform sizes in to a list of integers that can be consumed. */\n> > -\tstd::vector<int32_t> thumbnailEntries;\n> > -\tthumbnailEntries.reserve(thumbnailSizes.size() * 2);\n> > -\tfor (const auto &size : thumbnailSizes) {\n> > -\t\tthumbnailEntries.push_back(size.width);\n> > -\t\tthumbnailEntries.push_back(size.height);\n> > -\t}\n> > -\tstaticMetadata_->addEntry(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,\n> > -\t\t\t\t  thumbnailEntries);\n> > -\n> > -\tstaticMetadata_->addEntry(ANDROID_JPEG_MAX_SIZE, maxJpegBufferSize_);\n> > -\n> > -\t/* Sensor static metadata. */\n> > -\tstd::array<int32_t, 2> pixelArraySize;\n> > -\t{\n> > -\t\tconst Size &size = properties.get(properties::PixelArraySize);\n> > -\t\tpixelArraySize[0] = size.width;\n> > -\t\tpixelArraySize[1] = size.height;\n> > -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,\n> > -\t\t\t\t\t  pixelArraySize);\n> > -\t}\n> > -\n> > -\tif (properties.contains(properties::UnitCellSize)) {\n> > -\t\tconst Size &cellSize = properties.get<Size>(properties::UnitCellSize);\n> > -\t\tstd::array<float, 2> physicalSize{\n> > -\t\t\tcellSize.width * pixelArraySize[0] / 1e6f,\n> > -\t\t\tcellSize.height * pixelArraySize[1] / 1e6f\n> > -\t\t};\n> > -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,\n> > -\t\t\t\t\t  physicalSize);\n> > -\t}\n> > -\n> > -\t{\n> > -\t\tconst Span<const Rectangle> &rects =\n> > -\t\t\tproperties.get(properties::PixelArrayActiveAreas);\n> > -\t\tstd::vector<int32_t> data{\n> > -\t\t\tstatic_cast<int32_t>(rects[0].x),\n> > -\t\t\tstatic_cast<int32_t>(rects[0].y),\n> > -\t\t\tstatic_cast<int32_t>(rects[0].width),\n> > -\t\t\tstatic_cast<int32_t>(rects[0].height),\n> > -\t\t};\n> > -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,\n> > -\t\t\t\t\t  data);\n> > -\t}\n> > -\n> > -\tint32_t sensitivityRange[] = {\n> > -\t\t32, 2400,\n> > -\t};\n> > -\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,\n> > -\t\t\t\t  sensitivityRange);\n> > -\n> > -\t/* Report the color filter arrangement if the camera reports it. */\n> > -\tif (properties.contains(properties::draft::ColorFilterArrangement)) {\n> > -\t\tuint8_t filterArr = properties.get(properties::draft::ColorFilterArrangement);\n> > -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,\n> > -\t\t\t\t\t  filterArr);\n> > -\t}\n> > -\n> > -\tconst auto &exposureInfo = controlsInfo.find(&controls::ExposureTime);\n> > -\tif (exposureInfo != controlsInfo.end()) {\n> > -\t\tint64_t exposureTimeRange[2] = {\n> > -\t\t\texposureInfo->second.min().get<int32_t>() * 1000LL,\n> > -\t\t\texposureInfo->second.max().get<int32_t>() * 1000LL,\n> > -\t\t};\n> > -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,\n> > -\t\t\t\t\t  exposureTimeRange, 2);\n> > -\t}\n> > -\n> > -\tstaticMetadata_->addEntry(ANDROID_SENSOR_ORIENTATION, orientation_);\n> > -\n> > -\tstd::vector<int32_t> testPatternModes = {\n> > -\t\tANDROID_SENSOR_TEST_PATTERN_MODE_OFF\n> > -\t};\n> > -\tconst auto &testPatternsInfo =\n> > -\t\tcontrolsInfo.find(&controls::draft::TestPatternMode);\n> > -\tif (testPatternsInfo != controlsInfo.end()) {\n> > -\t\tconst auto &values = testPatternsInfo->second.values();\n> > -\t\tASSERT(!values.empty());\n> > -\t\tfor (const auto &value : values) {\n> > -\t\t\tswitch (value.get<int32_t>()) {\n> > -\t\t\tcase controls::draft::TestPatternModeOff:\n> > -\t\t\t\t/*\n> > -\t\t\t\t * ANDROID_SENSOR_TEST_PATTERN_MODE_OFF is\n> > -\t\t\t\t * already in testPatternModes.\n> > -\t\t\t\t */\n> > -\t\t\t\tbreak;\n> > -\n> > -\t\t\tcase controls::draft::TestPatternModeSolidColor:\n> > -\t\t\t\ttestPatternModes.push_back(\n> > -\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR);\n> > -\t\t\t\tbreak;\n> > -\n> > -\t\t\tcase controls::draft::TestPatternModeColorBars:\n> > -\t\t\t\ttestPatternModes.push_back(\n> > -\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS);\n> > -\t\t\t\tbreak;\n> > -\n> > -\t\t\tcase controls::draft::TestPatternModeColorBarsFadeToGray:\n> > -\t\t\t\ttestPatternModes.push_back(\n> > -\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY);\n> > -\t\t\t\tbreak;\n> > -\n> > -\t\t\tcase controls::draft::TestPatternModePn9:\n> > -\t\t\t\ttestPatternModes.push_back(\n> > -\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_PN9);\n> > -\t\t\t\tbreak;\n> > -\n> > -\t\t\tcase controls::draft::TestPatternModeCustom1:\n> > -\t\t\t\t/* We don't support this yet. */\n> > -\t\t\t\tbreak;\n> > -\n> > -\t\t\tdefault:\n> > -\t\t\t\tLOG(HAL, Error) << \"Unknown test pattern mode: \"\n> > -\t\t\t\t\t\t<< value.get<int32_t>();\n> > -\t\t\t\tcontinue;\n> > -\t\t\t}\n> > -\t\t}\n> > -\t}\n> > -\tstaticMetadata_->addEntry(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,\n> > -\t\t\t\t  testPatternModes);\n> > -\n> > -\tuint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;\n> > -\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,\n> > -\t\t\t\t  timestampSource);\n> > -\n> > -\tif (maxFrameDurationNsec > 0)\n> > -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,\n> > -\t\t\t\t\t  maxFrameDurationNsec);\n> > -\n> > -\t/* Statistics static metadata. */\n> > -\tuint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;\n> > -\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,\n> > -\t\t\t\t  faceDetectMode);\n> > -\n> > -\tint32_t maxFaceCount = 0;\n> > -\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,\n> > -\t\t\t\t  maxFaceCount);\n> > -\n> > -\t{\n> > -\t\tstd::vector<uint8_t> data;\n> > -\t\tdata.reserve(2);\n> > -\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::LensShadingMapMode);\n> > -\t\tif (infoMap != controlsInfo.end()) {\n> > -\t\t\tfor (const auto &value : infoMap->second.values())\n> > -\t\t\t\tdata.push_back(value.get<int32_t>());\n> > -\t\t} else {\n> > -\t\t\tdata.push_back(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF);\n> > -\t\t}\n> > -\t\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,\n> > -\t\t\t\t\t  data);\n> > -\t}\n> > -\n> > -\t/* Sync static metadata. */\n> > -\tint32_t maxLatency = ANDROID_SYNC_MAX_LATENCY_UNKNOWN;\n> > -\tstaticMetadata_->addEntry(ANDROID_SYNC_MAX_LATENCY, maxLatency);\n> > -\n> > -\t/* Flash static metadata. */\n> > -\tchar flashAvailable = ANDROID_FLASH_INFO_AVAILABLE_FALSE;\n> > -\tstaticMetadata_->addEntry(ANDROID_FLASH_INFO_AVAILABLE,\n> > -\t\t\t\t  flashAvailable);\n> > -\n> > -\t/* Lens static metadata. */\n> > -\tstd::vector<float> lensApertures = {\n> > -\t\t2.53 / 100,\n> > -\t};\n> > -\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_APERTURES,\n> > -\t\t\t\t  lensApertures);\n> > -\n> > -\tuint8_t lensFacing;\n> > -\tswitch (facing_) {\n> > -\tdefault:\n> > -\tcase CAMERA_FACING_FRONT:\n> > -\t\tlensFacing = ANDROID_LENS_FACING_FRONT;\n> > -\t\tbreak;\n> > -\tcase CAMERA_FACING_BACK:\n> > -\t\tlensFacing = ANDROID_LENS_FACING_BACK;\n> > -\t\tbreak;\n> > -\tcase CAMERA_FACING_EXTERNAL:\n> > -\t\tlensFacing = ANDROID_LENS_FACING_EXTERNAL;\n> > -\t\tbreak;\n> > -\t}\n> > -\tstaticMetadata_->addEntry(ANDROID_LENS_FACING, lensFacing);\n> > -\n> > -\tstd::vector<float> lensFocalLengths = {\n> > -\t\t1,\n> > -\t};\n> > -\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,\n> > -\t\t\t\t  lensFocalLengths);\n> > -\n> > -\tstd::vector<uint8_t> opticalStabilizations = {\n> > -\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF,\n> > -\t};\n> > -\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,\n> > -\t\t\t\t  opticalStabilizations);\n> > -\n> > -\tfloat hypeFocalDistance = 0;\n> > -\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,\n> > -\t\t\t\t  hypeFocalDistance);\n> > -\n> > -\tfloat minFocusDistance = 0;\n> > -\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,\n> > -\t\t\t\t  minFocusDistance);\n> > -\n> > -\t/* Noise reduction modes. */\n> > -\t{\n> > -\t\tstd::vector<uint8_t> data;\n> > -\t\tdata.reserve(5);\n> > -\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::NoiseReductionMode);\n> > -\t\tif (infoMap != controlsInfo.end()) {\n> > -\t\t\tfor (const auto &value : infoMap->second.values())\n> > -\t\t\t\tdata.push_back(value.get<int32_t>());\n> > -\t\t} else {\n> > -\t\t\tdata.push_back(ANDROID_NOISE_REDUCTION_MODE_OFF);\n> > -\t\t}\n> > -\t\tstaticMetadata_->addEntry(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,\n> > -\t\t\t\t\t  data);\n> > -\t}\n> > -\n> > -\t/* Scaler static metadata. */\n> > -\n> > -\t/*\n> > -\t * \\todo The digital zoom factor is a property that depends on the\n> > -\t * desired output configuration and the sensor frame size input to the\n> > -\t * ISP. This information is not available to the Android HAL, not at\n> > -\t * initialization time at least.\n> > -\t *\n> > -\t * As a workaround rely on pipeline handlers initializing the\n> > -\t * ScalerCrop control with the camera default configuration and use the\n> > -\t * maximum and minimum crop rectangles to calculate the digital zoom\n> > -\t * factor.\n> > -\t */\n> > -\tfloat maxZoom = 1.0f;\n> > -\tconst auto scalerCrop = controlsInfo.find(&controls::ScalerCrop);\n> > -\tif (scalerCrop != controlsInfo.end()) {\n> > -\t\tRectangle min = scalerCrop->second.min().get<Rectangle>();\n> > -\t\tRectangle max = scalerCrop->second.max().get<Rectangle>();\n> > -\t\tmaxZoom = std::min(1.0f * max.width / min.width,\n> > -\t\t\t\t   1.0f * max.height / min.height);\n> > -\t}\n> > -\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,\n> > -\t\t\t\t  maxZoom);\n> > -\n> > -\tstd::vector<uint32_t> availableStreamConfigurations;\n> > -\tavailableStreamConfigurations.reserve(streamConfigurations_.size() * 4);\n> > -\tfor (const auto &entry : streamConfigurations_) {\n> > -\t\tavailableStreamConfigurations.push_back(entry.androidFormat);\n> > -\t\tavailableStreamConfigurations.push_back(entry.resolution.width);\n> > -\t\tavailableStreamConfigurations.push_back(entry.resolution.height);\n> > -\t\tavailableStreamConfigurations.push_back(\n> > -\t\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);\n> > -\t}\n> > -\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,\n> > -\t\t\t\t  availableStreamConfigurations);\n> > -\n> > -\tstd::vector<int64_t> availableStallDurations = {\n> > -\t\tANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920, 33333333,\n> > -\t};\n> > -\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,\n> > -\t\t\t\t  availableStallDurations);\n> > -\n> > -\t/* Use the minimum frame duration for all the YUV/RGB formats. */\n> > -\tif (minFrameDurationNsec > 0) {\n> > -\t\tstd::vector<int64_t> minFrameDurations;\n> > -\t\tminFrameDurations.reserve(streamConfigurations_.size() * 4);\n> > -\t\tfor (const auto &entry : streamConfigurations_) {\n> > -\t\t\tminFrameDurations.push_back(entry.androidFormat);\n> > -\t\t\tminFrameDurations.push_back(entry.resolution.width);\n> > -\t\t\tminFrameDurations.push_back(entry.resolution.height);\n> > -\t\t\tminFrameDurations.push_back(minFrameDurationNsec);\n> > -\t\t}\n> > -\t\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,\n> > -\t\t\t\t\t  minFrameDurations);\n> > -\t}\n> > -\n> > -\tuint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY;\n> > -\tstaticMetadata_->addEntry(ANDROID_SCALER_CROPPING_TYPE, croppingType);\n> > -\n> > -\t/* Info static metadata. */\n> > -\tuint8_t supportedHWLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;\n> > -\tstaticMetadata_->addEntry(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,\n> > -\t\t\t\t  supportedHWLevel);\n> > -\n> > -\t/* Request static metadata. */\n> > -\tint32_t partialResultCount = 1;\n> > -\tstaticMetadata_->addEntry(ANDROID_REQUEST_PARTIAL_RESULT_COUNT,\n> > -\t\t\t\t  partialResultCount);\n> > -\n> > -\t{\n> > -\t\t/* Default the value to 2 if not reported by the camera. */\n> > -\t\tuint8_t maxPipelineDepth = 2;\n> > -\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::PipelineDepth);\n> > -\t\tif (infoMap != controlsInfo.end())\n> > -\t\t\tmaxPipelineDepth = infoMap->second.max().get<int32_t>();\n> > -\t\tstaticMetadata_->addEntry(ANDROID_REQUEST_PIPELINE_MAX_DEPTH,\n> > -\t\t\t\t\t  maxPipelineDepth);\n> > -\t}\n> > -\n> > -\t/* LIMITED does not support reprocessing. */\n> > -\tuint32_t maxNumInputStreams = 0;\n> > -\tstaticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,\n> > -\t\t\t\t  maxNumInputStreams);\n> > -\n> > -\tstd::vector<uint8_t> availableCapabilities = {\n> > -\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,\n> > -\t};\n> > -\n> > -\t/* Report if camera supports RAW. */\n> > -\tbool rawStreamAvailable = false;\n> > -\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> > -\t\tcamera_->generateConfiguration({ StreamRole::Raw });\n> > -\tif (cameraConfig && !cameraConfig->empty()) {\n> > -\t\tconst PixelFormatInfo &info =\n> > -\t\t\tPixelFormatInfo::info(cameraConfig->at(0).pixelFormat);\n> > -\t\t/* Only advertise RAW support if RAW16 is possible. */\n> > -\t\tif (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW &&\n> > -\t\t    info.bitsPerPixel == 16) {\n> > -\t\t\trawStreamAvailable = true;\n> > -\t\t\tavailableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);\n> > -\t\t}\n> > -\t}\n> > -\n> > -\t/* Number of { RAW, YUV, JPEG } supported output streams */\n> > -\tint32_t numOutStreams[] = { rawStreamAvailable, 2, 1 };\n> > -\tstaticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,\n> > -\t\t\t\t  numOutStreams);\n> > -\n> > -\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CAPABILITIES,\n> > -\t\t\t\t  availableCapabilities);\n> > -\n> > -\tstd::vector<int32_t> availableCharacteristicsKeys = {\n> > -\t\tANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,\n> > -\t\tANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,\n> > -\t\tANDROID_CONTROL_AE_AVAILABLE_MODES,\n> > -\t\tANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> > -\t\tANDROID_CONTROL_AE_COMPENSATION_RANGE,\n> > -\t\tANDROID_CONTROL_AE_COMPENSATION_STEP,\n> > -\t\tANDROID_CONTROL_AE_LOCK_AVAILABLE,\n> > -\t\tANDROID_CONTROL_AF_AVAILABLE_MODES,\n> > -\t\tANDROID_CONTROL_AVAILABLE_EFFECTS,\n> > -\t\tANDROID_CONTROL_AVAILABLE_MODES,\n> > -\t\tANDROID_CONTROL_AVAILABLE_SCENE_MODES,\n> > -\t\tANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,\n> > -\t\tANDROID_CONTROL_AWB_AVAILABLE_MODES,\n> > -\t\tANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> > -\t\tANDROID_CONTROL_MAX_REGIONS,\n> > -\t\tANDROID_CONTROL_SCENE_MODE_OVERRIDES,\n> > -\t\tANDROID_FLASH_INFO_AVAILABLE,\n> > -\t\tANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,\n> > -\t\tANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,\n> > -\t\tANDROID_JPEG_MAX_SIZE,\n> > -\t\tANDROID_LENS_FACING,\n> > -\t\tANDROID_LENS_INFO_AVAILABLE_APERTURES,\n> > -\t\tANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,\n> > -\t\tANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,\n> > -\t\tANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,\n> > -\t\tANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,\n> > -\t\tANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,\n> > -\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES,\n> > -\t\tANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,\n> > -\t\tANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,\n> > -\t\tANDROID_REQUEST_PARTIAL_RESULT_COUNT,\n> > -\t\tANDROID_REQUEST_PIPELINE_MAX_DEPTH,\n> > -\t\tANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,\n> > -\t\tANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,\n> > -\t\tANDROID_SCALER_AVAILABLE_STALL_DURATIONS,\n> > -\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,\n> > -\t\tANDROID_SCALER_CROPPING_TYPE,\n> > -\t\tANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,\n> > -\t\tANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,\n> > -\t\tANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,\n> > -\t\tANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,\n> > -\t\tANDROID_SENSOR_INFO_MAX_FRAME_DURATION,\n> > -\t\tANDROID_SENSOR_INFO_PHYSICAL_SIZE,\n> > -\t\tANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,\n> > -\t\tANDROID_SENSOR_INFO_SENSITIVITY_RANGE,\n> > -\t\tANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,\n> > -\t\tANDROID_SENSOR_ORIENTATION,\n> > -\t\tANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,\n> > -\t\tANDROID_STATISTICS_INFO_MAX_FACE_COUNT,\n> > -\t\tANDROID_SYNC_MAX_LATENCY,\n> > -\t};\n> > -\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,\n> > -\t\t\t\t  availableCharacteristicsKeys);\n> > -\n> > -\tstd::vector<int32_t> availableRequestKeys = {\n> > -\t\tANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> > -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> > -\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> > -\t\tANDROID_CONTROL_AE_LOCK,\n> > -\t\tANDROID_CONTROL_AE_MODE,\n> > -\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> > -\t\tANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> > -\t\tANDROID_CONTROL_AF_MODE,\n> > -\t\tANDROID_CONTROL_AF_TRIGGER,\n> > -\t\tANDROID_CONTROL_AWB_LOCK,\n> > -\t\tANDROID_CONTROL_AWB_MODE,\n> > -\t\tANDROID_CONTROL_CAPTURE_INTENT,\n> > -\t\tANDROID_CONTROL_EFFECT_MODE,\n> > -\t\tANDROID_CONTROL_MODE,\n> > -\t\tANDROID_CONTROL_SCENE_MODE,\n> > -\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE,\n> > -\t\tANDROID_FLASH_MODE,\n> > -\t\tANDROID_JPEG_ORIENTATION,\n> > -\t\tANDROID_JPEG_QUALITY,\n> > -\t\tANDROID_JPEG_THUMBNAIL_QUALITY,\n> > -\t\tANDROID_JPEG_THUMBNAIL_SIZE,\n> > -\t\tANDROID_LENS_APERTURE,\n> > -\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> > -\t\tANDROID_NOISE_REDUCTION_MODE,\n> > -\t\tANDROID_SCALER_CROP_REGION,\n> > -\t\tANDROID_STATISTICS_FACE_DETECT_MODE\n> > -\t};\n> > -\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,\n> > -\t\t\t\t  availableRequestKeys);\n> > -\n> > -\tstd::vector<int32_t> availableResultKeys = {\n> > -\t\tANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> > -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> > -\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> > -\t\tANDROID_CONTROL_AE_LOCK,\n> > -\t\tANDROID_CONTROL_AE_MODE,\n> > -\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> > -\t\tANDROID_CONTROL_AE_STATE,\n> > -\t\tANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> > -\t\tANDROID_CONTROL_AF_MODE,\n> > -\t\tANDROID_CONTROL_AF_STATE,\n> > -\t\tANDROID_CONTROL_AF_TRIGGER,\n> > -\t\tANDROID_CONTROL_AWB_LOCK,\n> > -\t\tANDROID_CONTROL_AWB_MODE,\n> > -\t\tANDROID_CONTROL_AWB_STATE,\n> > -\t\tANDROID_CONTROL_CAPTURE_INTENT,\n> > -\t\tANDROID_CONTROL_EFFECT_MODE,\n> > -\t\tANDROID_CONTROL_MODE,\n> > -\t\tANDROID_CONTROL_SCENE_MODE,\n> > -\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE,\n> > -\t\tANDROID_FLASH_MODE,\n> > -\t\tANDROID_FLASH_STATE,\n> > -\t\tANDROID_JPEG_GPS_COORDINATES,\n> > -\t\tANDROID_JPEG_GPS_PROCESSING_METHOD,\n> > -\t\tANDROID_JPEG_GPS_TIMESTAMP,\n> > -\t\tANDROID_JPEG_ORIENTATION,\n> > -\t\tANDROID_JPEG_QUALITY,\n> > -\t\tANDROID_JPEG_SIZE,\n> > -\t\tANDROID_JPEG_THUMBNAIL_QUALITY,\n> > -\t\tANDROID_JPEG_THUMBNAIL_SIZE,\n> > -\t\tANDROID_LENS_APERTURE,\n> > -\t\tANDROID_LENS_FOCAL_LENGTH,\n> > -\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> > -\t\tANDROID_LENS_STATE,\n> > -\t\tANDROID_NOISE_REDUCTION_MODE,\n> > -\t\tANDROID_REQUEST_PIPELINE_DEPTH,\n> > -\t\tANDROID_SCALER_CROP_REGION,\n> > -\t\tANDROID_SENSOR_EXPOSURE_TIME,\n> > -\t\tANDROID_SENSOR_FRAME_DURATION,\n> > -\t\tANDROID_SENSOR_ROLLING_SHUTTER_SKEW,\n> > -\t\tANDROID_SENSOR_TEST_PATTERN_MODE,\n> > -\t\tANDROID_SENSOR_TIMESTAMP,\n> > -\t\tANDROID_STATISTICS_FACE_DETECT_MODE,\n> > -\t\tANDROID_STATISTICS_LENS_SHADING_MAP_MODE,\n> > -\t\tANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,\n> > -\t\tANDROID_STATISTICS_SCENE_FLICKER,\n> > -\t};\n> > -\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,\n> > -\t\t\t\t  availableResultKeys);\n> > -\n> > -\tif (!staticMetadata_->isValid()) {\n> > -\t\tLOG(HAL, Error) << \"Failed to construct static metadata\";\n> > -\t\tstaticMetadata_.reset();\n> > -\t\treturn nullptr;\n> > -\t}\n> > -\n> > -\tif (staticMetadata_->resized()) {\n> > -\t\tauto [entryCount, dataCount] = staticMetadata_->usage();\n> > -\t\tLOG(HAL, Info)\n> > -\t\t\t<< \"Static metadata resized: \" << entryCount\n> > -\t\t\t<< \" entries and \" << dataCount << \" bytes used\";\n> > -\t}\n> > -\n> > -\treturn staticMetadata_->get();\n> > -}\n> > -\n> > -std::unique_ptr<CameraMetadata> CameraDevice::requestTemplatePreview()\n> > +void CameraDevice::setCallbacks(const camera3_callback_ops_t *callbacks)\n> >  {\n> > -\t/*\n> > -\t * \\todo Keep this in sync with the actual number of entries.\n> > -\t * Currently: 20 entries, 35 bytes\n> > -\t */\n> > -\tauto requestTemplate = std::make_unique<CameraMetadata>(21, 36);\n> > -\tif (!requestTemplate->isValid()) {\n> > -\t\treturn nullptr;\n> > -\t}\n> > -\n> > -\t/* Get the FPS range registered in the static metadata. */\n> > -\tcamera_metadata_ro_entry_t entry;\n> > -\tbool found = staticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> > -\t\t\t\t\t       &entry);\n> > -\tif (!found) {\n> > -\t\tLOG(HAL, Error) << \"Cannot create capture template without FPS range\";\n> > -\t\treturn nullptr;\n> > -\t}\n> > -\n> > -\t/*\n> > -\t * Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata\n> > -\t * has been assembled as {{min, max} {max, max}}.\n> > -\t */\n> > -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> > -\t\t\t\t  entry.data.i32, 2);\n> > -\n> > -\tuint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;\n> > -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_MODE, aeMode);\n> > -\n> > -\tint32_t aeExposureCompensation = 0;\n> > -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> > -\t\t\t\t  aeExposureCompensation);\n> > -\n> > -\tuint8_t aePrecaptureTrigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;\n> > -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> > -\t\t\t\t  aePrecaptureTrigger);\n> > -\n> > -\tuint8_t aeLock = ANDROID_CONTROL_AE_LOCK_OFF;\n> > -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_LOCK, aeLock);\n> > -\n> > -\tuint8_t aeAntibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;\n> > -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> > -\t\t\t\t  aeAntibandingMode);\n> > -\n> > -\tuint8_t afMode = ANDROID_CONTROL_AF_MODE_OFF;\n> > -\trequestTemplate->addEntry(ANDROID_CONTROL_AF_MODE, afMode);\n> > -\n> > -\tuint8_t afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;\n> > -\trequestTemplate->addEntry(ANDROID_CONTROL_AF_TRIGGER, afTrigger);\n> > -\n> > -\tuint8_t awbMode = ANDROID_CONTROL_AWB_MODE_AUTO;\n> > -\trequestTemplate->addEntry(ANDROID_CONTROL_AWB_MODE, awbMode);\n> > -\n> > -\tuint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;\n> > -\trequestTemplate->addEntry(ANDROID_CONTROL_AWB_LOCK, awbLock);\n> > -\n> > -\tuint8_t flashMode = ANDROID_FLASH_MODE_OFF;\n> > -\trequestTemplate->addEntry(ANDROID_FLASH_MODE, flashMode);\n> > -\n> > -\tuint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;\n> > -\trequestTemplate->addEntry(ANDROID_STATISTICS_FACE_DETECT_MODE,\n> > -\t\t\t\t  faceDetectMode);\n> > -\n> > -\tuint8_t noiseReduction = ANDROID_NOISE_REDUCTION_MODE_OFF;\n> > -\trequestTemplate->addEntry(ANDROID_NOISE_REDUCTION_MODE,\n> > -\t\t\t\t  noiseReduction);\n> > -\n> > -\tuint8_t aberrationMode = ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF;\n> > -\trequestTemplate->addEntry(ANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> > -\t\t\t\t  aberrationMode);\n> > -\n> > -\tuint8_t controlMode = ANDROID_CONTROL_MODE_AUTO;\n> > -\trequestTemplate->addEntry(ANDROID_CONTROL_MODE, controlMode);\n> > -\n> > -\tfloat lensAperture = 2.53 / 100;\n> > -\trequestTemplate->addEntry(ANDROID_LENS_APERTURE, lensAperture);\n> > -\n> > -\tuint8_t opticalStabilization = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;\n> > -\trequestTemplate->addEntry(ANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> > -\t\t\t\t  opticalStabilization);\n> > -\n> > -\tuint8_t captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;\n> > -\trequestTemplate->addEntry(ANDROID_CONTROL_CAPTURE_INTENT,\n> > -\t\t\t\t  captureIntent);\n> > -\n> > -\treturn requestTemplate;\n> > +\tcallbacks_ = callbacks;\n> >  }\n> >\n> > -std::unique_ptr<CameraMetadata> CameraDevice::requestTemplateVideo()\n> > +const camera_metadata_t *CameraDevice::getStaticMetadata()\n> >  {\n> > -\tstd::unique_ptr<CameraMetadata> previewTemplate = requestTemplatePreview();\n> > -\tif (!previewTemplate)\n> > -\t\treturn nullptr;\n> > -\n> > -\t/*\n> > -\t * The video template requires a fixed FPS range. Everything else\n> > -\t * stays the same as the preview template.\n> > -\t */\n> > -\tcamera_metadata_ro_entry_t entry;\n> > -\tstaticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> > -\t\t\t\t  &entry);\n> > -\n> > -\t/*\n> > -\t * Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata\n> > -\t * has been assembled as {{min, max} {max, max}}.\n> > -\t */\n> > -\tpreviewTemplate->updateEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> > -\t\t\t\t     entry.data.i32 + 2, 2);\n> > -\n> > -\treturn previewTemplate;\n> > +\treturn capabilities_.staticMetadata()->get();\n> >  }\n> >\n> >  /*\n> > @@ -1630,7 +520,7 @@ const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type)\n> >  \tswitch (type) {\n> >  \tcase CAMERA3_TEMPLATE_PREVIEW:\n> >  \t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;\n> > -\t\trequestTemplate = requestTemplatePreview();\n> > +\t\trequestTemplate = capabilities_.requestTemplatePreview();\n> >  \t\tbreak;\n> >  \tcase CAMERA3_TEMPLATE_STILL_CAPTURE:\n> >  \t\t/*\n> > @@ -1638,15 +528,15 @@ const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type)\n> >  \t\t * for the torch mode we currently do not support.\n> >  \t\t */\n> >  \t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;\n> > -\t\trequestTemplate = requestTemplatePreview();\n> > +\t\trequestTemplate = capabilities_.requestTemplatePreview();\n> >  \t\tbreak;\n> >  \tcase CAMERA3_TEMPLATE_VIDEO_RECORD:\n> >  \t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;\n> > -\t\trequestTemplate = requestTemplateVideo();\n> > +\t\trequestTemplate = capabilities_.requestTemplateVideo();\n> >  \t\tbreak;\n> >  \tcase CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:\n> >  \t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;\n> > -\t\trequestTemplate = requestTemplateVideo();\n> > +\t\trequestTemplate = capabilities_.requestTemplateVideo();\n> >  \t\tbreak;\n> >  \t/* \\todo Implement templates generation for the remaining use cases. */\n> >  \tcase CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:\n> > @@ -1668,19 +558,6 @@ const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type)\n> >  \treturn requestTemplates_[type]->get();\n> >  }\n> >\n> > -PixelFormat CameraDevice::toPixelFormat(int format) const\n> > -{\n> > -\t/* Translate Android format code to libcamera pixel format. */\n> > -\tauto it = formatsMap_.find(format);\n> > -\tif (it == formatsMap_.end()) {\n> > -\t\tLOG(HAL, Error) << \"Requested format \" << utils::hex(format)\n> > -\t\t\t\t<< \" not supported\";\n> > -\t\treturn PixelFormat();\n> > -\t}\n> > -\n> > -\treturn it->second;\n> > -}\n> > -\n> >  /*\n> >   * Inspect the stream_list to produce a list of StreamConfiguration to\n> >   * be use to configure the Camera.\n> > @@ -1727,7 +604,7 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)\n> >  \t\tcamera3_stream_t *stream = stream_list->streams[i];\n> >  \t\tSize size(stream->width, stream->height);\n> >\n> > -\t\tPixelFormat format = toPixelFormat(stream->format);\n> > +\t\tPixelFormat format = capabilities_.toPixelFormat(stream->format);\n> >\n> >  \t\tLOG(HAL, Info) << \"Stream #\" << i\n> >  \t\t\t       << \", direction: \" << stream->stream_type\n> > diff --git a/src/android/camera_device.h b/src/android/camera_device.h\n> > index 4aadb27c562c..090fe28a551e 100644\n> > --- a/src/android/camera_device.h\n> > +++ b/src/android/camera_device.h\n> > @@ -10,14 +10,12 @@\n> >  #include <map>\n> >  #include <memory>\n> >  #include <mutex>\n> > -#include <tuple>\n> >  #include <vector>\n> >\n> >  #include <hardware/camera3.h>\n> >\n> >  #include <libcamera/buffer.h>\n> >  #include <libcamera/camera.h>\n> > -#include <libcamera/geometry.h>\n> >  #include <libcamera/request.h>\n> >  #include <libcamera/stream.h>\n> >\n> > @@ -26,6 +24,7 @@\n> >  #include \"libcamera/internal/message.h\"\n> >  #include \"libcamera/internal/thread.h\"\n> >\n> > +#include \"camera_capabilities.h\"\n> >  #include \"camera_metadata.h\"\n> >  #include \"camera_stream.h\"\n> >  #include \"camera_worker.h\"\n> > @@ -57,7 +56,7 @@ public:\n> >  \tconst std::string &model() const { return model_; }\n> >  \tint facing() const { return facing_; }\n> >  \tint orientation() const { return orientation_; }\n> > -\tunsigned int maxJpegBufferSize() const { return maxJpegBufferSize_; }\n> > +\tunsigned int maxJpegBufferSize() const;\n> >\n> >  \tvoid setCallbacks(const camera3_callback_ops_t *callbacks);\n> >  \tconst camera_metadata_t *getStaticMetadata();\n> > @@ -86,11 +85,6 @@ private:\n> >  \t\tstd::unique_ptr<CaptureRequest> request_;\n> >  \t};\n> >\n> > -\tstruct Camera3StreamConfiguration {\n> > -\t\tlibcamera::Size resolution;\n> > -\t\tint androidFormat;\n> > -\t};\n> > -\n> >  \tenum class State {\n> >  \t\tStopped,\n> >  \t\tFlushing,\n> > @@ -99,22 +93,11 @@ private:\n> >\n> >  \tvoid stop();\n> >\n> > -\tint initializeStreamConfigurations();\n> > -\tstd::vector<libcamera::Size>\n> > -\tgetYUVResolutions(libcamera::CameraConfiguration *cameraConfig,\n> > -\t\t\t  const libcamera::PixelFormat &pixelFormat,\n> > -\t\t\t  const std::vector<libcamera::Size> &resolutions);\n> > -\tstd::vector<libcamera::Size>\n> > -\tgetRawResolutions(const libcamera::PixelFormat &pixelFormat);\n> > -\n> >  \tlibcamera::FrameBuffer *createFrameBuffer(const buffer_handle_t camera3buffer);\n> >  \tvoid abortRequest(camera3_capture_request_t *request);\n> >  \tvoid notifyShutter(uint32_t frameNumber, uint64_t timestamp);\n> >  \tvoid notifyError(uint32_t frameNumber, camera3_stream_t *stream,\n> >  \t\t\t camera3_error_msg_code code);\n> > -\tstd::unique_ptr<CameraMetadata> requestTemplatePreview();\n> > -\tstd::unique_ptr<CameraMetadata> requestTemplateVideo();\n> > -\tlibcamera::PixelFormat toPixelFormat(int format) const;\n> >  \tint processControls(Camera3RequestDescriptor *descriptor);\n> >  \tstd::unique_ptr<CameraMetadata> getResultMetadata(\n> >  \t\tconst Camera3RequestDescriptor &descriptor) const;\n> > @@ -129,13 +112,11 @@ private:\n> >\n> >  \tstd::shared_ptr<libcamera::Camera> camera_;\n> >  \tstd::unique_ptr<libcamera::CameraConfiguration> config_;\n> > +\tCameraCapabilities capabilities_;\n> >\n> > -\tstd::unique_ptr<CameraMetadata> staticMetadata_;\n> >  \tstd::map<unsigned int, std::unique_ptr<CameraMetadata>> requestTemplates_;\n> >  \tconst camera3_callback_ops_t *callbacks_;\n> >\n> > -\tstd::vector<Camera3StreamConfiguration> streamConfigurations_;\n> > -\tstd::map<int, libcamera::PixelFormat> formatsMap_;\n> >  \tstd::vector<CameraStream> streams_;\n> >\n> >  \tlibcamera::Mutex descriptorsMutex_; /* Protects descriptors_. */\n> > @@ -147,8 +128,6 @@ private:\n> >  \tint facing_;\n> >  \tint orientation_;\n> >\n> > -\tunsigned int maxJpegBufferSize_;\n> > -\n> >  \tCameraMetadata lastSettings_;\n> >  };\n> >\n> > diff --git a/src/android/meson.build b/src/android/meson.build\n> > index 3893e5b5b832..e093aa2ec565 100644\n> > --- a/src/android/meson.build\n> > +++ b/src/android/meson.build\n> > @@ -45,6 +45,7 @@ subdir('cros')\n> >  android_hal_sources = files([\n> >      'camera3_hal.cpp',\n> >      'camera_hal_manager.cpp',\n> > +    'camera_capabilities.cpp',\n>\n> While at it, could you sort this alphabetically ?\n>\n\nSure, maybe in a patch before this one.\n\nThanks\n   j\n\n> >      'camera_device.cpp',\n> >      'camera_hal_config.cpp',\n> >      'camera_metadata.cpp',\n>\n> --\n> Regards,\n>\n> Laurent Pinchart","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id D7EADBE58C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 21 Jun 2021 13:52:59 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 659D66893A;\n\tMon, 21 Jun 2021 15:52:59 +0200 (CEST)","from relay7-d.mail.gandi.net (relay7-d.mail.gandi.net\n\t[217.70.183.200])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 1485860295\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 21 Jun 2021 15:52:58 +0200 (CEST)","(Authenticated sender: jacopo@jmondi.org)\n\tby relay7-d.mail.gandi.net (Postfix) with ESMTPSA id EB1FC20011;\n\tMon, 21 Jun 2021 13:52:56 +0000 (UTC)"],"Date":"Mon, 21 Jun 2021 15:53:45 +0200","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Message-ID":"<20210621135345.a3gug5ei6zxqjnif@uno.localdomain>","References":"<20210619105151.20012-1-jacopo@jmondi.org>\n\t<20210619105151.20012-2-jacopo@jmondi.org>\n\t<YM6V63Kmy3/2zU/Y@pendragon.ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<YM6V63Kmy3/2zU/Y@pendragon.ideasonboard.com>","Subject":"Re: [libcamera-devel] [RFC 1/1] android: Introduce\n\tCameraCapabilties class","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":17663,"web_url":"https://patchwork.libcamera.org/comment/17663/","msgid":"<YNCc7twXlDjkEYn9@pendragon.ideasonboard.com>","date":"2021-06-21T14:06:38","subject":"Re: [libcamera-devel] [RFC 1/1] android: Introduce\n\tCameraCapabilties class","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Jacopo,\n\nOn Mon, Jun 21, 2021 at 03:53:45PM +0200, Jacopo Mondi wrote:\n> On Sun, Jun 20, 2021 at 04:12:11AM +0300, Laurent Pinchart wrote:\n> > On Sat, Jun 19, 2021 at 12:51:51PM +0200, Jacopo Mondi wrote:\n> > > The camera_device.cpp has grown a little too much, and it has quickly\n> > > become hard to maintain. Break out the handling of the static\n> > > information collected at camera initialization time to a new\n> > > CameraCapabilities class.\n> > >\n> > > Break out from the camera_device.cpp file all the functions relative to:\n> > > - Initialization of supported stream configurations\n> > > - Initialization of static metadata\n> > > - Initialization of request templates\n> > >\n> > > Signed-off-by: Jacopo Mondi <jacopo@jmondi.org>\n> > > ---\n> > >  src/android/camera_capabilities.cpp | 1165 +++++++++++++++++++++++++++\n> > >  src/android/camera_capabilities.h   |   64 ++\n> > >  src/android/camera_device.cpp       | 1147 +-------------------------\n> > >  src/android/camera_device.h         |   27 +-\n> > >  src/android/meson.build             |    1 +\n> > >  5 files changed, 1245 insertions(+), 1159 deletions(-)\n> > >  create mode 100644 src/android/camera_capabilities.cpp\n> > >  create mode 100644 src/android/camera_capabilities.h\n> > >\n> > > diff --git a/src/android/camera_capabilities.cpp b/src/android/camera_capabilities.cpp\n> > > new file mode 100644\n> > > index 000000000000..20df9a6f1abb\n> > > --- /dev/null\n> > > +++ b/src/android/camera_capabilities.cpp\n> > > @@ -0,0 +1,1165 @@\n> > > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > > +/*\n> > > + * Copyright (C) 2021, Google Inc.\n> > > + *\n> > > + * camera_capabilities.cpp - Camera static properties manager\n> > > + */\n> > > +\n> > > +#include \"camera_capabilities.h\"\n> > > +\n> > > +#include <array>\n> > > +#include <cmath>\n> > > +\n> > > +#include <hardware/camera3.h>\n> > > +\n> > > +#include <libcamera/control_ids.h>\n> > > +#include <libcamera/controls.h>\n> > > +#include <libcamera/formats.h>\n> > > +#include <libcamera/property_ids.h>\n> > > +\n> > > +#include \"libcamera/internal/formats.h\"\n> > > +#include \"libcamera/internal/log.h\"\n> > > +\n> > > +using namespace libcamera;\n> > > +\n> > > +LOG_DECLARE_CATEGORY(HAL)\n> > > +\n> > > +namespace {\n> > > +\n> > > +/*\n> > > + * \\var camera3Resolutions\n> > > + * \\brief The list of image resolutions defined as mandatory to be supported by\n> > > + * the Android Camera3 specification\n> > > + */\n> > > +const std::vector<Size> camera3Resolutions = {\n> > > +\t{ 320, 240 },\n> > > +\t{ 640, 480 },\n> > > +\t{ 1280, 720 },\n> > > +\t{ 1920, 1080 }\n> > > +};\n> > > +\n> > > +/*\n> > > + * \\struct Camera3Format\n> > > + * \\brief Data associated with an Android format identifier\n> > > + * \\var libcameraFormats List of libcamera pixel formats compatible with the\n> > > + * Android format\n> > > + * \\var name The human-readable representation of the Android format code\n> > > + */\n> > > +struct Camera3Format {\n> > > +\tstd::vector<PixelFormat> libcameraFormats;\n> > > +\tbool mandatory;\n> > > +\tconst char *name;\n> > > +};\n> > > +\n> > > +/*\n> > > + * \\var camera3FormatsMap\n> > > + * \\brief Associate Android format code with ancillary data\n> > > + */\n> > > +const std::map<int, const Camera3Format> camera3FormatsMap = {\n> > > +\t{\n> > > +\t\tHAL_PIXEL_FORMAT_BLOB, {\n> > > +\t\t\t{ formats::MJPEG },\n> > > +\t\t\ttrue,\n> > > +\t\t\t\"BLOB\"\n> > > +\t\t}\n> > > +\t}, {\n> > > +\t\tHAL_PIXEL_FORMAT_YCbCr_420_888, {\n> > > +\t\t\t{ formats::NV12, formats::NV21 },\n> > > +\t\t\ttrue,\n> > > +\t\t\t\"YCbCr_420_888\"\n> > > +\t\t}\n> > > +\t}, {\n> > > +\t\t/*\n> > > +\t\t * \\todo Translate IMPLEMENTATION_DEFINED inspecting the gralloc\n> > > +\t\t * usage flag. For now, copy the YCbCr_420 configuration.\n> > > +\t\t */\n> > > +\t\tHAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, {\n> > > +\t\t\t{ formats::NV12, formats::NV21 },\n> > > +\t\t\ttrue,\n> > > +\t\t\t\"IMPLEMENTATION_DEFINED\"\n> > > +\t\t}\n> > > +\t}, {\n> > > +\t\tHAL_PIXEL_FORMAT_RAW10, {\n> > > +\t\t\t{\n> > > +\t\t\t\tformats::SBGGR10_CSI2P,\n> > > +\t\t\t\tformats::SGBRG10_CSI2P,\n> > > +\t\t\t\tformats::SGRBG10_CSI2P,\n> > > +\t\t\t\tformats::SRGGB10_CSI2P\n> > > +\t\t\t},\n> > > +\t\t\tfalse,\n> > > +\t\t\t\"RAW10\"\n> > > +\t\t}\n> > > +\t}, {\n> > > +\t\tHAL_PIXEL_FORMAT_RAW12, {\n> > > +\t\t\t{\n> > > +\t\t\t\tformats::SBGGR12_CSI2P,\n> > > +\t\t\t\tformats::SGBRG12_CSI2P,\n> > > +\t\t\t\tformats::SGRBG12_CSI2P,\n> > > +\t\t\t\tformats::SRGGB12_CSI2P\n> > > +\t\t\t},\n> > > +\t\t\tfalse,\n> > > +\t\t\t\"RAW12\"\n> > > +\t\t}\n> > > +\t}, {\n> > > +\t\tHAL_PIXEL_FORMAT_RAW16, {\n> > > +\t\t\t{\n> > > +\t\t\t\tformats::SBGGR16,\n> > > +\t\t\t\tformats::SGBRG16,\n> > > +\t\t\t\tformats::SGRBG16,\n> > > +\t\t\t\tformats::SRGGB16\n> > > +\t\t\t},\n> > > +\t\t\tfalse,\n> > > +\t\t\t\"RAW16\"\n> > > +\t\t}\n> > > +\t},\n> > > +};\n> > > +\n> > > +} /* namespace */\n> > > +\n> > > +int CameraCapabilities::initialize(std::shared_ptr<libcamera::Camera> camera,\n> > > +\t\t\t\t   int orientation, int facing)\n> > > +{\n> > > +\tcamera_ = camera;\n> > > +\torientation_ = orientation;\n> > > +\tfacing_ = facing;\n> > > +\n> > > +\t/* Acquire the camera and initialize available stream configurations. */\n> > > +\tint ret = camera_->acquire();\n> > > +\tif (ret) {\n> > > +\t\tLOG(HAL, Error) << \"Failed to temporarily acquire the camera\";\n> > > +\t\treturn ret;\n> > > +\t}\n> > > +\n> > > +\tret = initializeStreamConfigurations();\n> > > +\tcamera_->release();\n> > > +\tif (ret)\n> > > +\t\treturn ret;\n> > > +\n> > > +\treturn initializeStaticMetadata();\n> > > +}\n> > > +\n> > > +std::vector<Size> CameraCapabilities::getYUVResolutions(CameraConfiguration *cameraConfig,\n> > > +\t\t\t\t\t\t\tconst PixelFormat &pixelFormat,\n> > > +\t\t\t\t\t\t\tconst std::vector<Size> &resolutions)\n> > > +{\n> > > +\tstd::vector<Size> supportedResolutions;\n> > > +\n> > > +\tStreamConfiguration &cfg = cameraConfig->at(0);\n> > > +\tfor (const Size &res : resolutions) {\n> > > +\t\tcfg.pixelFormat = pixelFormat;\n> > > +\t\tcfg.size = res;\n> > > +\n> > > +\t\tCameraConfiguration::Status status = cameraConfig->validate();\n> > > +\t\tif (status != CameraConfiguration::Valid) {\n> > > +\t\t\tLOG(HAL, Debug) << cfg.toString() << \" not supported\";\n> > > +\t\t\tcontinue;\n> > > +\t\t}\n> > > +\n> > > +\t\tLOG(HAL, Debug) << cfg.toString() << \" supported\";\n> > > +\n> > > +\t\tsupportedResolutions.push_back(res);\n> > > +\t}\n> > > +\n> > > +\treturn supportedResolutions;\n> > > +}\n> > > +\n> > > +std::vector<Size> CameraCapabilities::getRawResolutions(const libcamera::PixelFormat &pixelFormat)\n> > > +{\n> > > +\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> > > +\t\tcamera_->generateConfiguration({ StreamRole::Raw });\n> > > +\tStreamConfiguration &cfg = cameraConfig->at(0);\n> > > +\tconst StreamFormats &formats = cfg.formats();\n> > > +\tstd::vector<Size> supportedResolutions = formats.sizes(pixelFormat);\n> > > +\n> > > +\treturn supportedResolutions;\n> > > +}\n> > > +\n> > > +/*\n> > > + * Initialize the format conversion map to translate from Android format\n> > > + * identifier to libcamera pixel formats and fill in the list of supported\n> > > + * stream configurations to be reported to the Android camera framework through\n> > > + * the Camera static metadata.\n> > > + */\n> > > +int CameraCapabilities::initializeStreamConfigurations()\n> > > +{\n> > > +\t/*\n> > > +\t * Get the maximum output resolutions\n> > > +\t * \\todo Get this from the camera properties once defined\n> > > +\t */\n> > > +\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> > > +\t\tcamera_->generateConfiguration({ StillCapture });\n> > > +\tif (!cameraConfig) {\n> > > +\t\tLOG(HAL, Error) << \"Failed to get maximum resolution\";\n> > > +\t\treturn -EINVAL;\n> > > +\t}\n> > > +\tStreamConfiguration &cfg = cameraConfig->at(0);\n> > > +\n> > > +\t/*\n> > > +\t * \\todo JPEG - Adjust the maximum available resolution by taking the\n> > > +\t * JPEG encoder requirements into account (alignment and aspect ratio).\n> > > +\t */\n> > > +\tconst Size maxRes = cfg.size;\n> > > +\tLOG(HAL, Debug) << \"Maximum supported resolution: \" << maxRes.toString();\n> > > +\n> > > +\t/*\n> > > +\t * Build the list of supported image resolutions.\n> > > +\t *\n> > > +\t * The resolutions listed in camera3Resolution are mandatory to be\n> > > +\t * supported, up to the camera maximum resolution.\n> > > +\t *\n> > > +\t * Augment the list by adding resolutions calculated from the camera\n> > > +\t * maximum one.\n> > > +\t */\n> > > +\tstd::vector<Size> cameraResolutions;\n> > > +\tstd::copy_if(camera3Resolutions.begin(), camera3Resolutions.end(),\n> > > +\t\t     std::back_inserter(cameraResolutions),\n> > > +\t\t     [&](const Size &res) { return res < maxRes; });\n> > > +\n> > > +\t/*\n> > > +\t * The Camera3 specification suggests adding 1/2 and 1/4 of the maximum\n> > > +\t * resolution.\n> > > +\t */\n> > > +\tfor (unsigned int divider = 2;; divider <<= 1) {\n> > > +\t\tSize derivedSize{\n> > > +\t\t\tmaxRes.width / divider,\n> > > +\t\t\tmaxRes.height / divider,\n> > > +\t\t};\n> > > +\n> > > +\t\tif (derivedSize.width < 320 ||\n> > > +\t\t    derivedSize.height < 240)\n> > > +\t\t\tbreak;\n> > > +\n> > > +\t\tcameraResolutions.push_back(derivedSize);\n> > > +\t}\n> > > +\tcameraResolutions.push_back(maxRes);\n> > > +\n> > > +\t/* Remove duplicated entries from the list of supported resolutions. */\n> > > +\tstd::sort(cameraResolutions.begin(), cameraResolutions.end());\n> > > +\tauto last = std::unique(cameraResolutions.begin(), cameraResolutions.end());\n> > > +\tcameraResolutions.erase(last, cameraResolutions.end());\n> > > +\n> > > +\t/*\n> > > +\t * Build the list of supported camera formats.\n> > > +\t *\n> > > +\t * To each Android format a list of compatible libcamera formats is\n> > > +\t * associated. The first libcamera format that tests successful is added\n> > > +\t * to the format translation map used when configuring the streams.\n> > > +\t * It is then tested against the list of supported camera resolutions to\n> > > +\t * build the stream configuration map reported through the camera static\n> > > +\t * metadata.\n> > > +\t */\n> > > +\tSize maxJpegSize;\n> > > +\tfor (const auto &format : camera3FormatsMap) {\n> > > +\t\tint androidFormat = format.first;\n> > > +\t\tconst Camera3Format &camera3Format = format.second;\n> > > +\t\tconst std::vector<PixelFormat> &libcameraFormats =\n> > > +\t\t\tcamera3Format.libcameraFormats;\n> > > +\n> > > +\t\tLOG(HAL, Debug) << \"Trying to map Android format \"\n> > > +\t\t\t\t<< camera3Format.name;\n> > > +\n> > > +\t\t/*\n> > > +\t\t * JPEG is always supported, either produced directly by the\n> > > +\t\t * camera, or encoded in the HAL.\n> > > +\t\t */\n> > > +\t\tif (androidFormat == HAL_PIXEL_FORMAT_BLOB) {\n> > > +\t\t\tformatsMap_[androidFormat] = formats::MJPEG;\n> > > +\t\t\tLOG(HAL, Debug) << \"Mapped Android format \"\n> > > +\t\t\t\t\t<< camera3Format.name << \" to \"\n> > > +\t\t\t\t\t<< formats::MJPEG.toString()\n> > > +\t\t\t\t\t<< \" (fixed mapping)\";\n> > > +\t\t\tcontinue;\n> > > +\t\t}\n> > > +\n> > > +\t\t/*\n> > > +\t\t * Test the libcamera formats that can produce images\n> > > +\t\t * compatible with the format defined by Android.\n> > > +\t\t */\n> > > +\t\tPixelFormat mappedFormat;\n> > > +\t\tfor (const PixelFormat &pixelFormat : libcameraFormats) {\n> > > +\n> > > +\t\t\tLOG(HAL, Debug) << \"Testing \" << pixelFormat.toString();\n> > > +\n> > > +\t\t\t/*\n> > > +\t\t\t * The stream configuration size can be adjusted,\n> > > +\t\t\t * not the pixel format.\n> > > +\t\t\t *\n> > > +\t\t\t * \\todo This could be simplified once all pipeline\n> > > +\t\t\t * handlers will report the StreamFormats list of\n> > > +\t\t\t * supported formats.\n> > > +\t\t\t */\n> > > +\t\t\tcfg.pixelFormat = pixelFormat;\n> > > +\n> > > +\t\t\tCameraConfiguration::Status status = cameraConfig->validate();\n> > > +\t\t\tif (status != CameraConfiguration::Invalid &&\n> > > +\t\t\t    cfg.pixelFormat == pixelFormat) {\n> > > +\t\t\t\tmappedFormat = pixelFormat;\n> > > +\t\t\t\tbreak;\n> > > +\t\t\t}\n> > > +\t\t}\n> > > +\n> > > +\t\tif (!mappedFormat.isValid()) {\n> > > +\t\t\t/* If the format is not mandatory, skip it. */\n> > > +\t\t\tif (!camera3Format.mandatory)\n> > > +\t\t\t\tcontinue;\n> > > +\n> > > +\t\t\tLOG(HAL, Error)\n> > > +\t\t\t\t<< \"Failed to map mandatory Android format \"\n> > > +\t\t\t\t<< camera3Format.name << \" (\"\n> > > +\t\t\t\t<< utils::hex(androidFormat) << \"): aborting\";\n> > > +\t\t\treturn -EINVAL;\n> > > +\t\t}\n> > > +\n> > > +\t\t/*\n> > > +\t\t * Record the mapping and then proceed to generate the\n> > > +\t\t * stream configurations map, by testing the image resolutions.\n> > > +\t\t */\n> > > +\t\tformatsMap_[androidFormat] = mappedFormat;\n> > > +\t\tLOG(HAL, Debug) << \"Mapped Android format \"\n> > > +\t\t\t\t<< camera3Format.name << \" to \"\n> > > +\t\t\t\t<< mappedFormat.toString();\n> > > +\n> > > +\t\tstd::vector<Size> resolutions;\n> > > +\t\tconst PixelFormatInfo &info = PixelFormatInfo::info(mappedFormat);\n> > > +\t\tif (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW)\n> > > +\t\t\tresolutions = getRawResolutions(mappedFormat);\n> > > +\t\telse\n> > > +\t\t\tresolutions = getYUVResolutions(cameraConfig.get(),\n> > > +\t\t\t\t\t\t\tmappedFormat,\n> > > +\t\t\t\t\t\t\tcameraResolutions);\n> > > +\n> > > +\t\tfor (const Size &res : resolutions) {\n> > > +\t\t\tstreamConfigurations_.push_back({ res, androidFormat });\n> > > +\n> > > +\t\t\t/*\n> > > +\t\t\t * If the format is HAL_PIXEL_FORMAT_YCbCr_420_888\n> > > +\t\t\t * from which JPEG is produced, add an entry for\n> > > +\t\t\t * the JPEG stream.\n> > > +\t\t\t *\n> > > +\t\t\t * \\todo Wire the JPEG encoder to query the supported\n> > > +\t\t\t * sizes provided a list of formats it can encode.\n> > > +\t\t\t *\n> > > +\t\t\t * \\todo Support JPEG streams produced by the Camera\n> > > +\t\t\t * natively.\n> > > +\t\t\t */\n> > > +\t\t\tif (androidFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {\n> > > +\t\t\t\tstreamConfigurations_.push_back(\n> > > +\t\t\t\t\t{ res, HAL_PIXEL_FORMAT_BLOB });\n> > > +\t\t\t\tmaxJpegSize = std::max(maxJpegSize, res);\n> > > +\t\t\t}\n> > > +\t\t}\n> > > +\n> > > +\t\t/*\n> > > +\t\t * \\todo Calculate the maximum JPEG buffer size by asking the\n> > > +\t\t * encoder giving the maximum frame size required.\n> > > +\t\t */\n> > > +\t\tmaxJpegBufferSize_ = maxJpegSize.width * maxJpegSize.height * 1.5;\n> > > +\t}\n> > > +\n> > > +\tLOG(HAL, Debug) << \"Collected stream configuration map: \";\n> > > +\tfor (const auto &entry : streamConfigurations_)\n> > > +\t\tLOG(HAL, Debug) << \"{ \" << entry.resolution.toString() << \" - \"\n> > > +\t\t\t\t<< utils::hex(entry.androidFormat) << \" }\";\n> > > +\n> > > +\treturn 0;\n> > > +}\n> > > +\n> > > +int CameraCapabilities::initializeStaticMetadata()\n> > > +{\n> > > +\tstaticMetadata_ = std::make_unique<CameraMetadata>(64, 1024);\n> > > +\tif (!staticMetadata_->isValid()) {\n> > > +\t\tLOG(HAL, Error) << \"Failed to allocate static metadata\";\n> > > +\t\tstaticMetadata_.reset();\n> > > +\t\treturn -EINVAL;\n> > > +\t}\n> > > +\n> > > +\tconst ControlInfoMap &controlsInfo = camera_->controls();\n> > > +\tconst ControlList &properties = camera_->properties();\n> > > +\n> > > +\t/* Color correction static metadata. */\n> > > +\t{\n> > > +\t\tstd::vector<uint8_t> data;\n> > > +\t\tdata.reserve(3);\n> > > +\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::ColorCorrectionAberrationMode);\n> > > +\t\tif (infoMap != controlsInfo.end()) {\n> > > +\t\t\tfor (const auto &value : infoMap->second.values())\n> > > +\t\t\t\tdata.push_back(value.get<int32_t>());\n> > > +\t\t} else {\n> > > +\t\t\tdata.push_back(ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF);\n> > > +\t\t}\n> > > +\t\tstaticMetadata_->addEntry(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,\n> > > +\t\t\t\t\t  data);\n> > > +\t}\n> > > +\n> > > +\t/* Control static metadata. */\n> > > +\tstd::vector<uint8_t> aeAvailableAntiBandingModes = {\n> > > +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF,\n> > > +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ,\n> > > +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ,\n> > > +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO,\n> > > +\t};\n> > > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,\n> > > +\t\t\t\t  aeAvailableAntiBandingModes);\n> > > +\n> > > +\tstd::vector<uint8_t> aeAvailableModes = {\n> > > +\t\tANDROID_CONTROL_AE_MODE_ON,\n> > > +\t};\n> > > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_MODES,\n> > > +\t\t\t\t  aeAvailableModes);\n> > > +\n> > > +\tint64_t minFrameDurationNsec = -1;\n> > > +\tint64_t maxFrameDurationNsec = -1;\n> > > +\tconst auto frameDurationsInfo = controlsInfo.find(&controls::FrameDurationLimits);\n> > > +\tif (frameDurationsInfo != controlsInfo.end()) {\n> > > +\t\tminFrameDurationNsec = frameDurationsInfo->second.min().get<int64_t>() * 1000;\n> > > +\t\tmaxFrameDurationNsec = frameDurationsInfo->second.max().get<int64_t>() * 1000;\n> > > +\n> > > +\t\t/*\n> > > +\t\t * Adjust the minimum frame duration to comply with Android\n> > > +\t\t * requirements. The camera service mandates all preview/record\n> > > +\t\t * streams to have a minimum frame duration < 33,366 milliseconds\n> > > +\t\t * (see MAX_PREVIEW_RECORD_DURATION_NS in the camera service\n> > > +\t\t * implementation).\n> > > +\t\t *\n> > > +\t\t * If we're close enough (+ 500 useconds) to that value, round\n> > > +\t\t * the minimum frame duration of the camera to an accepted\n> > > +\t\t * value.\n> > > +\t\t */\n> > > +\t\tstatic constexpr int64_t MAX_PREVIEW_RECORD_DURATION_NS = 1e9 / 29.97;\n> > > +\t\tif (minFrameDurationNsec > MAX_PREVIEW_RECORD_DURATION_NS &&\n> > > +\t\t    minFrameDurationNsec < MAX_PREVIEW_RECORD_DURATION_NS + 500000)\n> > > +\t\t\tminFrameDurationNsec = MAX_PREVIEW_RECORD_DURATION_NS - 1000;\n> > > +\n> > > +\t\t/*\n> > > +\t\t * The AE routine frame rate limits are computed using the frame\n> > > +\t\t * duration limits, as libcamera clips the AE routine to the\n> > > +\t\t * frame durations.\n> > > +\t\t */\n> > > +\t\tint32_t maxFps = std::round(1e9 / minFrameDurationNsec);\n> > > +\t\tint32_t minFps = std::round(1e9 / maxFrameDurationNsec);\n> > > +\t\tminFps = std::max(1, minFps);\n> > > +\n> > > +\t\t/*\n> > > +\t\t * Force rounding errors so that we have the proper frame\n> > > +\t\t * durations for when we reuse these variables later\n> > > +\t\t */\n> > > +\t\tminFrameDurationNsec = 1e9 / maxFps;\n> > > +\t\tmaxFrameDurationNsec = 1e9 / minFps;\n> > > +\n> > > +\t\t/*\n> > > +\t\t * Register to the camera service {min, max} and {max, max}\n> > > +\t\t * intervals as requested by the metadata documentation.\n> > > +\t\t */\n> > > +\t\tint32_t availableAeFpsTarget[] = {\n> > > +\t\t\tminFps, maxFps, maxFps, maxFps\n> > > +\t\t};\n> > > +\t\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> > > +\t\t\t\t\t  availableAeFpsTarget);\n> > > +\t}\n> > > +\n> > > +\tstd::vector<int32_t> aeCompensationRange = {\n> > > +\t\t0, 0,\n> > > +\t};\n> > > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_RANGE,\n> > > +\t\t\t\t  aeCompensationRange);\n> > > +\n> > > +\tconst camera_metadata_rational_t aeCompensationStep[] = {\n> > > +\t\t{ 0, 1 }\n> > > +\t};\n> > > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_STEP,\n> > > +\t\t\t\t  aeCompensationStep);\n> > > +\n> > > +\tstd::vector<uint8_t> availableAfModes = {\n> > > +\t\tANDROID_CONTROL_AF_MODE_OFF,\n> > > +\t};\n> > > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AF_AVAILABLE_MODES,\n> > > +\t\t\t\t  availableAfModes);\n> > > +\n> > > +\tstd::vector<uint8_t> availableEffects = {\n> > > +\t\tANDROID_CONTROL_EFFECT_MODE_OFF,\n> > > +\t};\n> > > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_EFFECTS,\n> > > +\t\t\t\t  availableEffects);\n> > > +\n> > > +\tstd::vector<uint8_t> availableSceneModes = {\n> > > +\t\tANDROID_CONTROL_SCENE_MODE_DISABLED,\n> > > +\t};\n> > > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_SCENE_MODES,\n> > > +\t\t\t\t  availableSceneModes);\n> > > +\n> > > +\tstd::vector<uint8_t> availableStabilizationModes = {\n> > > +\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF,\n> > > +\t};\n> > > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,\n> > > +\t\t\t\t  availableStabilizationModes);\n> > > +\n> > > +\t/*\n> > > +\t * \\todo Inspect the Camera capabilities to report the available\n> > > +\t * AWB modes. Default to AUTO as CTS tests require it.\n> > > +\t */\n> > > +\tstd::vector<uint8_t> availableAwbModes = {\n> > > +\t\tANDROID_CONTROL_AWB_MODE_AUTO,\n> > > +\t};\n> > > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AWB_AVAILABLE_MODES,\n> > > +\t\t\t\t  availableAwbModes);\n> > > +\n> > > +\tstd::vector<int32_t> availableMaxRegions = {\n> > > +\t\t0, 0, 0,\n> > > +\t};\n> > > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_MAX_REGIONS,\n> > > +\t\t\t\t  availableMaxRegions);\n> > > +\n> > > +\tstd::vector<uint8_t> sceneModesOverride = {\n> > > +\t\tANDROID_CONTROL_AE_MODE_ON,\n> > > +\t\tANDROID_CONTROL_AWB_MODE_AUTO,\n> > > +\t\tANDROID_CONTROL_AF_MODE_OFF,\n> > > +\t};\n> > > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_SCENE_MODE_OVERRIDES,\n> > > +\t\t\t\t  sceneModesOverride);\n> > > +\n> > > +\tuint8_t aeLockAvailable = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE;\n> > > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE,\n> > > +\t\t\t\t  aeLockAvailable);\n> > > +\n> > > +\tuint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;\n> > > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> > > +\t\t\t\t  awbLockAvailable);\n> > > +\n> > > +\tchar availableControlModes = ANDROID_CONTROL_MODE_AUTO;\n> > > +\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_MODES,\n> > > +\t\t\t\t  availableControlModes);\n> > > +\n> > > +\t/* JPEG static metadata. */\n> > > +\n> > > +\t/*\n> > > +\t * Create the list of supported thumbnail sizes by inspecting the\n> > > +\t * available JPEG resolutions collected in streamConfigurations_ and\n> > > +\t * generate one entry for each aspect ratio.\n> > > +\t *\n> > > +\t * The JPEG thumbnailer can freely scale, so pick an arbitrary\n> > > +\t * (160, 160) size as the bounding rectangle, which is then cropped to\n> > > +\t * the different supported aspect ratios.\n> > > +\t */\n> > > +\tconstexpr Size maxJpegThumbnail(160, 160);\n> > > +\tstd::vector<Size> thumbnailSizes;\n> > > +\tthumbnailSizes.push_back({ 0, 0 });\n> > > +\tfor (const auto &entry : streamConfigurations_) {\n> > > +\t\tif (entry.androidFormat != HAL_PIXEL_FORMAT_BLOB)\n> > > +\t\t\tcontinue;\n> > > +\n> > > +\t\tSize thumbnailSize = maxJpegThumbnail\n> > > +\t\t\t\t     .boundedToAspectRatio({ entry.resolution.width,\n> > > +\t\t\t\t\t\t\t     entry.resolution.height });\n> > > +\t\tthumbnailSizes.push_back(thumbnailSize);\n> > > +\t}\n> > > +\n> > > +\tstd::sort(thumbnailSizes.begin(), thumbnailSizes.end());\n> > > +\tauto last = std::unique(thumbnailSizes.begin(), thumbnailSizes.end());\n> > > +\tthumbnailSizes.erase(last, thumbnailSizes.end());\n> > > +\n> > > +\t/* Transform sizes in to a list of integers that can be consumed. */\n> > > +\tstd::vector<int32_t> thumbnailEntries;\n> > > +\tthumbnailEntries.reserve(thumbnailSizes.size() * 2);\n> > > +\tfor (const auto &size : thumbnailSizes) {\n> > > +\t\tthumbnailEntries.push_back(size.width);\n> > > +\t\tthumbnailEntries.push_back(size.height);\n> > > +\t}\n> > > +\tstaticMetadata_->addEntry(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,\n> > > +\t\t\t\t  thumbnailEntries);\n> > > +\n> > > +\tstaticMetadata_->addEntry(ANDROID_JPEG_MAX_SIZE, maxJpegBufferSize_);\n> > > +\n> > > +\t/* Sensor static metadata. */\n> > > +\tstd::array<int32_t, 2> pixelArraySize;\n> > > +\t{\n> > > +\t\tconst Size &size = properties.get(properties::PixelArraySize);\n> > > +\t\tpixelArraySize[0] = size.width;\n> > > +\t\tpixelArraySize[1] = size.height;\n> > > +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,\n> > > +\t\t\t\t\t  pixelArraySize);\n> > > +\t}\n> > > +\n> > > +\tif (properties.contains(properties::UnitCellSize)) {\n> > > +\t\tconst Size &cellSize = properties.get<Size>(properties::UnitCellSize);\n> > > +\t\tstd::array<float, 2> physicalSize{\n> > > +\t\t\tcellSize.width * pixelArraySize[0] / 1e6f,\n> > > +\t\t\tcellSize.height * pixelArraySize[1] / 1e6f\n> > > +\t\t};\n> > > +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,\n> > > +\t\t\t\t\t  physicalSize);\n> > > +\t}\n> > > +\n> > > +\t{\n> > > +\t\tconst Span<const Rectangle> &rects =\n> > > +\t\t\tproperties.get(properties::PixelArrayActiveAreas);\n> > > +\t\tstd::vector<int32_t> data{\n> > > +\t\t\tstatic_cast<int32_t>(rects[0].x),\n> > > +\t\t\tstatic_cast<int32_t>(rects[0].y),\n> > > +\t\t\tstatic_cast<int32_t>(rects[0].width),\n> > > +\t\t\tstatic_cast<int32_t>(rects[0].height),\n> > > +\t\t};\n> > > +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,\n> > > +\t\t\t\t\t  data);\n> > > +\t}\n> > > +\n> > > +\tint32_t sensitivityRange[] = {\n> > > +\t\t32, 2400,\n> > > +\t};\n> > > +\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,\n> > > +\t\t\t\t  sensitivityRange);\n> > > +\n> > > +\t/* Report the color filter arrangement if the camera reports it. */\n> > > +\tif (properties.contains(properties::draft::ColorFilterArrangement)) {\n> > > +\t\tuint8_t filterArr = properties.get(properties::draft::ColorFilterArrangement);\n> > > +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,\n> > > +\t\t\t\t\t  filterArr);\n> > > +\t}\n> > > +\n> > > +\tconst auto &exposureInfo = controlsInfo.find(&controls::ExposureTime);\n> > > +\tif (exposureInfo != controlsInfo.end()) {\n> > > +\t\tint64_t exposureTimeRange[2] = {\n> > > +\t\t\texposureInfo->second.min().get<int32_t>() * 1000LL,\n> > > +\t\t\texposureInfo->second.max().get<int32_t>() * 1000LL,\n> > > +\t\t};\n> > > +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,\n> > > +\t\t\t\t\t  exposureTimeRange, 2);\n> > > +\t}\n> > > +\n> > > +\tstaticMetadata_->addEntry(ANDROID_SENSOR_ORIENTATION, orientation_);\n> > > +\n> > > +\tstd::vector<int32_t> testPatternModes = {\n> > > +\t\tANDROID_SENSOR_TEST_PATTERN_MODE_OFF\n> > > +\t};\n> > > +\tconst auto &testPatternsInfo =\n> > > +\t\tcontrolsInfo.find(&controls::draft::TestPatternMode);\n> > > +\tif (testPatternsInfo != controlsInfo.end()) {\n> > > +\t\tconst auto &values = testPatternsInfo->second.values();\n> > > +\t\tASSERT(!values.empty());\n> > > +\t\tfor (const auto &value : values) {\n> > > +\t\t\tswitch (value.get<int32_t>()) {\n> > > +\t\t\tcase controls::draft::TestPatternModeOff:\n> > > +\t\t\t\t/*\n> > > +\t\t\t\t * ANDROID_SENSOR_TEST_PATTERN_MODE_OFF is\n> > > +\t\t\t\t * already in testPatternModes.\n> > > +\t\t\t\t */\n> > > +\t\t\t\tbreak;\n> > > +\n> > > +\t\t\tcase controls::draft::TestPatternModeSolidColor:\n> > > +\t\t\t\ttestPatternModes.push_back(\n> > > +\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR);\n> > > +\t\t\t\tbreak;\n> > > +\n> > > +\t\t\tcase controls::draft::TestPatternModeColorBars:\n> > > +\t\t\t\ttestPatternModes.push_back(\n> > > +\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS);\n> > > +\t\t\t\tbreak;\n> > > +\n> > > +\t\t\tcase controls::draft::TestPatternModeColorBarsFadeToGray:\n> > > +\t\t\t\ttestPatternModes.push_back(\n> > > +\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY);\n> > > +\t\t\t\tbreak;\n> > > +\n> > > +\t\t\tcase controls::draft::TestPatternModePn9:\n> > > +\t\t\t\ttestPatternModes.push_back(\n> > > +\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_PN9);\n> > > +\t\t\t\tbreak;\n> > > +\n> > > +\t\t\tcase controls::draft::TestPatternModeCustom1:\n> > > +\t\t\t\t/* We don't support this yet. */\n> > > +\t\t\t\tbreak;\n> > > +\n> > > +\t\t\tdefault:\n> > > +\t\t\t\tLOG(HAL, Error) << \"Unknown test pattern mode: \"\n> > > +\t\t\t\t\t\t<< value.get<int32_t>();\n> > > +\t\t\t\tcontinue;\n> > > +\t\t\t}\n> > > +\t\t}\n> > > +\t}\n> > > +\tstaticMetadata_->addEntry(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,\n> > > +\t\t\t\t  testPatternModes);\n> > > +\n> > > +\tuint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;\n> > > +\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,\n> > > +\t\t\t\t  timestampSource);\n> > > +\n> > > +\tif (maxFrameDurationNsec > 0)\n> > > +\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,\n> > > +\t\t\t\t\t  maxFrameDurationNsec);\n> > > +\n> > > +\t/* Statistics static metadata. */\n> > > +\tuint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;\n> > > +\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,\n> > > +\t\t\t\t  faceDetectMode);\n> > > +\n> > > +\tint32_t maxFaceCount = 0;\n> > > +\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,\n> > > +\t\t\t\t  maxFaceCount);\n> > > +\n> > > +\t{\n> > > +\t\tstd::vector<uint8_t> data;\n> > > +\t\tdata.reserve(2);\n> > > +\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::LensShadingMapMode);\n> > > +\t\tif (infoMap != controlsInfo.end()) {\n> > > +\t\t\tfor (const auto &value : infoMap->second.values())\n> > > +\t\t\t\tdata.push_back(value.get<int32_t>());\n> > > +\t\t} else {\n> > > +\t\t\tdata.push_back(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF);\n> > > +\t\t}\n> > > +\t\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,\n> > > +\t\t\t\t\t  data);\n> > > +\t}\n> > > +\n> > > +\t/* Sync static metadata. */\n> > > +\tint32_t maxLatency = ANDROID_SYNC_MAX_LATENCY_UNKNOWN;\n> > > +\tstaticMetadata_->addEntry(ANDROID_SYNC_MAX_LATENCY, maxLatency);\n> > > +\n> > > +\t/* Flash static metadata. */\n> > > +\tchar flashAvailable = ANDROID_FLASH_INFO_AVAILABLE_FALSE;\n> > > +\tstaticMetadata_->addEntry(ANDROID_FLASH_INFO_AVAILABLE,\n> > > +\t\t\t\t  flashAvailable);\n> > > +\n> > > +\t/* Lens static metadata. */\n> > > +\tstd::vector<float> lensApertures = {\n> > > +\t\t2.53 / 100,\n> > > +\t};\n> > > +\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_APERTURES,\n> > > +\t\t\t\t  lensApertures);\n> > > +\n> > > +\tuint8_t lensFacing;\n> > > +\tswitch (facing_) {\n> > > +\tdefault:\n> > > +\tcase CAMERA_FACING_FRONT:\n> > > +\t\tlensFacing = ANDROID_LENS_FACING_FRONT;\n> > > +\t\tbreak;\n> > > +\tcase CAMERA_FACING_BACK:\n> > > +\t\tlensFacing = ANDROID_LENS_FACING_BACK;\n> > > +\t\tbreak;\n> > > +\tcase CAMERA_FACING_EXTERNAL:\n> > > +\t\tlensFacing = ANDROID_LENS_FACING_EXTERNAL;\n> > > +\t\tbreak;\n> > > +\t}\n> > > +\tstaticMetadata_->addEntry(ANDROID_LENS_FACING, lensFacing);\n> > > +\n> > > +\tstd::vector<float> lensFocalLengths = {\n> > > +\t\t1,\n> > > +\t};\n> > > +\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,\n> > > +\t\t\t\t  lensFocalLengths);\n> > > +\n> > > +\tstd::vector<uint8_t> opticalStabilizations = {\n> > > +\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF,\n> > > +\t};\n> > > +\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,\n> > > +\t\t\t\t  opticalStabilizations);\n> > > +\n> > > +\tfloat hypeFocalDistance = 0;\n> > > +\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,\n> > > +\t\t\t\t  hypeFocalDistance);\n> > > +\n> > > +\tfloat minFocusDistance = 0;\n> > > +\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,\n> > > +\t\t\t\t  minFocusDistance);\n> > > +\n> > > +\t/* Noise reduction modes. */\n> > > +\t{\n> > > +\t\tstd::vector<uint8_t> data;\n> > > +\t\tdata.reserve(5);\n> > > +\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::NoiseReductionMode);\n> > > +\t\tif (infoMap != controlsInfo.end()) {\n> > > +\t\t\tfor (const auto &value : infoMap->second.values())\n> > > +\t\t\t\tdata.push_back(value.get<int32_t>());\n> > > +\t\t} else {\n> > > +\t\t\tdata.push_back(ANDROID_NOISE_REDUCTION_MODE_OFF);\n> > > +\t\t}\n> > > +\t\tstaticMetadata_->addEntry(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,\n> > > +\t\t\t\t\t  data);\n> > > +\t}\n> > > +\n> > > +\t/* Scaler static metadata. */\n> > > +\n> > > +\t/*\n> > > +\t * \\todo The digital zoom factor is a property that depends on the\n> > > +\t * desired output configuration and the sensor frame size input to the\n> > > +\t * ISP. This information is not available to the Android HAL, not at\n> > > +\t * initialization time at least.\n> > > +\t *\n> > > +\t * As a workaround rely on pipeline handlers initializing the\n> > > +\t * ScalerCrop control with the camera default configuration and use the\n> > > +\t * maximum and minimum crop rectangles to calculate the digital zoom\n> > > +\t * factor.\n> > > +\t */\n> > > +\tfloat maxZoom = 1.0f;\n> > > +\tconst auto scalerCrop = controlsInfo.find(&controls::ScalerCrop);\n> > > +\tif (scalerCrop != controlsInfo.end()) {\n> > > +\t\tRectangle min = scalerCrop->second.min().get<Rectangle>();\n> > > +\t\tRectangle max = scalerCrop->second.max().get<Rectangle>();\n> > > +\t\tmaxZoom = std::min(1.0f * max.width / min.width,\n> > > +\t\t\t\t   1.0f * max.height / min.height);\n> > > +\t}\n> > > +\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,\n> > > +\t\t\t\t  maxZoom);\n> > > +\n> > > +\tstd::vector<uint32_t> availableStreamConfigurations;\n> > > +\tavailableStreamConfigurations.reserve(streamConfigurations_.size() * 4);\n> > > +\tfor (const auto &entry : streamConfigurations_) {\n> > > +\t\tavailableStreamConfigurations.push_back(entry.androidFormat);\n> > > +\t\tavailableStreamConfigurations.push_back(entry.resolution.width);\n> > > +\t\tavailableStreamConfigurations.push_back(entry.resolution.height);\n> > > +\t\tavailableStreamConfigurations.push_back(\n> > > +\t\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);\n> > > +\t}\n> > > +\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,\n> > > +\t\t\t\t  availableStreamConfigurations);\n> > > +\n> > > +\tstd::vector<int64_t> availableStallDurations = {\n> > > +\t\tANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920, 33333333,\n> > > +\t};\n> > > +\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,\n> > > +\t\t\t\t  availableStallDurations);\n> > > +\n> > > +\t/* Use the minimum frame duration for all the YUV/RGB formats. */\n> > > +\tif (minFrameDurationNsec > 0) {\n> > > +\t\tstd::vector<int64_t> minFrameDurations;\n> > > +\t\tminFrameDurations.reserve(streamConfigurations_.size() * 4);\n> > > +\t\tfor (const auto &entry : streamConfigurations_) {\n> > > +\t\t\tminFrameDurations.push_back(entry.androidFormat);\n> > > +\t\t\tminFrameDurations.push_back(entry.resolution.width);\n> > > +\t\t\tminFrameDurations.push_back(entry.resolution.height);\n> > > +\t\t\tminFrameDurations.push_back(minFrameDurationNsec);\n> > > +\t\t}\n> > > +\t\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,\n> > > +\t\t\t\t\t  minFrameDurations);\n> > > +\t}\n> > > +\n> > > +\tuint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY;\n> > > +\tstaticMetadata_->addEntry(ANDROID_SCALER_CROPPING_TYPE, croppingType);\n> > > +\n> > > +\t/* Info static metadata. */\n> > > +\tuint8_t supportedHWLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;\n> > > +\tstaticMetadata_->addEntry(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,\n> > > +\t\t\t\t  supportedHWLevel);\n> > > +\n> > > +\t/* Request static metadata. */\n> > > +\tint32_t partialResultCount = 1;\n> > > +\tstaticMetadata_->addEntry(ANDROID_REQUEST_PARTIAL_RESULT_COUNT,\n> > > +\t\t\t\t  partialResultCount);\n> > > +\n> > > +\t{\n> > > +\t\t/* Default the value to 2 if not reported by the camera. */\n> > > +\t\tuint8_t maxPipelineDepth = 2;\n> > > +\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::PipelineDepth);\n> > > +\t\tif (infoMap != controlsInfo.end())\n> > > +\t\t\tmaxPipelineDepth = infoMap->second.max().get<int32_t>();\n> > > +\t\tstaticMetadata_->addEntry(ANDROID_REQUEST_PIPELINE_MAX_DEPTH,\n> > > +\t\t\t\t\t  maxPipelineDepth);\n> > > +\t}\n> > > +\n> > > +\t/* LIMITED does not support reprocessing. */\n> > > +\tuint32_t maxNumInputStreams = 0;\n> > > +\tstaticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,\n> > > +\t\t\t\t  maxNumInputStreams);\n> > > +\n> > > +\tstd::vector<uint8_t> availableCapabilities = {\n> > > +\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,\n> > > +\t};\n> > > +\n> > > +\t/* Report if camera supports RAW. */\n> > > +\tbool rawStreamAvailable = false;\n> > > +\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> > > +\t\tcamera_->generateConfiguration({ StreamRole::Raw });\n> > > +\tif (cameraConfig && !cameraConfig->empty()) {\n> > > +\t\tconst PixelFormatInfo &info =\n> > > +\t\t\tPixelFormatInfo::info(cameraConfig->at(0).pixelFormat);\n> > > +\t\t/* Only advertise RAW support if RAW16 is possible. */\n> > > +\t\tif (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW &&\n> > > +\t\t    info.bitsPerPixel == 16) {\n> > > +\t\t\trawStreamAvailable = true;\n> > > +\t\t\tavailableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);\n> > > +\t\t}\n> > > +\t}\n> > > +\n> > > +\t/* Number of { RAW, YUV, JPEG } supported output streams */\n> > > +\tint32_t numOutStreams[] = { rawStreamAvailable, 2, 1 };\n> > > +\tstaticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,\n> > > +\t\t\t\t  numOutStreams);\n> > > +\n> > > +\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CAPABILITIES,\n> > > +\t\t\t\t  availableCapabilities);\n> > > +\n> > > +\tstd::vector<int32_t> availableCharacteristicsKeys = {\n> > > +\t\tANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,\n> > > +\t\tANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,\n> > > +\t\tANDROID_CONTROL_AE_AVAILABLE_MODES,\n> > > +\t\tANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> > > +\t\tANDROID_CONTROL_AE_COMPENSATION_RANGE,\n> > > +\t\tANDROID_CONTROL_AE_COMPENSATION_STEP,\n> > > +\t\tANDROID_CONTROL_AE_LOCK_AVAILABLE,\n> > > +\t\tANDROID_CONTROL_AF_AVAILABLE_MODES,\n> > > +\t\tANDROID_CONTROL_AVAILABLE_EFFECTS,\n> > > +\t\tANDROID_CONTROL_AVAILABLE_MODES,\n> > > +\t\tANDROID_CONTROL_AVAILABLE_SCENE_MODES,\n> > > +\t\tANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,\n> > > +\t\tANDROID_CONTROL_AWB_AVAILABLE_MODES,\n> > > +\t\tANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> > > +\t\tANDROID_CONTROL_MAX_REGIONS,\n> > > +\t\tANDROID_CONTROL_SCENE_MODE_OVERRIDES,\n> > > +\t\tANDROID_FLASH_INFO_AVAILABLE,\n> > > +\t\tANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,\n> > > +\t\tANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,\n> > > +\t\tANDROID_JPEG_MAX_SIZE,\n> > > +\t\tANDROID_LENS_FACING,\n> > > +\t\tANDROID_LENS_INFO_AVAILABLE_APERTURES,\n> > > +\t\tANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,\n> > > +\t\tANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,\n> > > +\t\tANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,\n> > > +\t\tANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,\n> > > +\t\tANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,\n> > > +\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES,\n> > > +\t\tANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,\n> > > +\t\tANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,\n> > > +\t\tANDROID_REQUEST_PARTIAL_RESULT_COUNT,\n> > > +\t\tANDROID_REQUEST_PIPELINE_MAX_DEPTH,\n> > > +\t\tANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,\n> > > +\t\tANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,\n> > > +\t\tANDROID_SCALER_AVAILABLE_STALL_DURATIONS,\n> > > +\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,\n> > > +\t\tANDROID_SCALER_CROPPING_TYPE,\n> > > +\t\tANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,\n> > > +\t\tANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,\n> > > +\t\tANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,\n> > > +\t\tANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,\n> > > +\t\tANDROID_SENSOR_INFO_MAX_FRAME_DURATION,\n> > > +\t\tANDROID_SENSOR_INFO_PHYSICAL_SIZE,\n> > > +\t\tANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,\n> > > +\t\tANDROID_SENSOR_INFO_SENSITIVITY_RANGE,\n> > > +\t\tANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,\n> > > +\t\tANDROID_SENSOR_ORIENTATION,\n> > > +\t\tANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,\n> > > +\t\tANDROID_STATISTICS_INFO_MAX_FACE_COUNT,\n> > > +\t\tANDROID_SYNC_MAX_LATENCY,\n> > > +\t};\n> > > +\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,\n> > > +\t\t\t\t  availableCharacteristicsKeys);\n> > > +\n> > > +\tstd::vector<int32_t> availableRequestKeys = {\n> > > +\t\tANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> > > +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> > > +\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> > > +\t\tANDROID_CONTROL_AE_LOCK,\n> > > +\t\tANDROID_CONTROL_AE_MODE,\n> > > +\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> > > +\t\tANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> > > +\t\tANDROID_CONTROL_AF_MODE,\n> > > +\t\tANDROID_CONTROL_AF_TRIGGER,\n> > > +\t\tANDROID_CONTROL_AWB_LOCK,\n> > > +\t\tANDROID_CONTROL_AWB_MODE,\n> > > +\t\tANDROID_CONTROL_CAPTURE_INTENT,\n> > > +\t\tANDROID_CONTROL_EFFECT_MODE,\n> > > +\t\tANDROID_CONTROL_MODE,\n> > > +\t\tANDROID_CONTROL_SCENE_MODE,\n> > > +\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE,\n> > > +\t\tANDROID_FLASH_MODE,\n> > > +\t\tANDROID_JPEG_ORIENTATION,\n> > > +\t\tANDROID_JPEG_QUALITY,\n> > > +\t\tANDROID_JPEG_THUMBNAIL_QUALITY,\n> > > +\t\tANDROID_JPEG_THUMBNAIL_SIZE,\n> > > +\t\tANDROID_LENS_APERTURE,\n> > > +\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> > > +\t\tANDROID_NOISE_REDUCTION_MODE,\n> > > +\t\tANDROID_SCALER_CROP_REGION,\n> > > +\t\tANDROID_STATISTICS_FACE_DETECT_MODE\n> > > +\t};\n> > > +\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,\n> > > +\t\t\t\t  availableRequestKeys);\n> > > +\n> > > +\tstd::vector<int32_t> availableResultKeys = {\n> > > +\t\tANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> > > +\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> > > +\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> > > +\t\tANDROID_CONTROL_AE_LOCK,\n> > > +\t\tANDROID_CONTROL_AE_MODE,\n> > > +\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> > > +\t\tANDROID_CONTROL_AE_STATE,\n> > > +\t\tANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> > > +\t\tANDROID_CONTROL_AF_MODE,\n> > > +\t\tANDROID_CONTROL_AF_STATE,\n> > > +\t\tANDROID_CONTROL_AF_TRIGGER,\n> > > +\t\tANDROID_CONTROL_AWB_LOCK,\n> > > +\t\tANDROID_CONTROL_AWB_MODE,\n> > > +\t\tANDROID_CONTROL_AWB_STATE,\n> > > +\t\tANDROID_CONTROL_CAPTURE_INTENT,\n> > > +\t\tANDROID_CONTROL_EFFECT_MODE,\n> > > +\t\tANDROID_CONTROL_MODE,\n> > > +\t\tANDROID_CONTROL_SCENE_MODE,\n> > > +\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE,\n> > > +\t\tANDROID_FLASH_MODE,\n> > > +\t\tANDROID_FLASH_STATE,\n> > > +\t\tANDROID_JPEG_GPS_COORDINATES,\n> > > +\t\tANDROID_JPEG_GPS_PROCESSING_METHOD,\n> > > +\t\tANDROID_JPEG_GPS_TIMESTAMP,\n> > > +\t\tANDROID_JPEG_ORIENTATION,\n> > > +\t\tANDROID_JPEG_QUALITY,\n> > > +\t\tANDROID_JPEG_SIZE,\n> > > +\t\tANDROID_JPEG_THUMBNAIL_QUALITY,\n> > > +\t\tANDROID_JPEG_THUMBNAIL_SIZE,\n> > > +\t\tANDROID_LENS_APERTURE,\n> > > +\t\tANDROID_LENS_FOCAL_LENGTH,\n> > > +\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> > > +\t\tANDROID_LENS_STATE,\n> > > +\t\tANDROID_NOISE_REDUCTION_MODE,\n> > > +\t\tANDROID_REQUEST_PIPELINE_DEPTH,\n> > > +\t\tANDROID_SCALER_CROP_REGION,\n> > > +\t\tANDROID_SENSOR_EXPOSURE_TIME,\n> > > +\t\tANDROID_SENSOR_FRAME_DURATION,\n> > > +\t\tANDROID_SENSOR_ROLLING_SHUTTER_SKEW,\n> > > +\t\tANDROID_SENSOR_TEST_PATTERN_MODE,\n> > > +\t\tANDROID_SENSOR_TIMESTAMP,\n> > > +\t\tANDROID_STATISTICS_FACE_DETECT_MODE,\n> > > +\t\tANDROID_STATISTICS_LENS_SHADING_MAP_MODE,\n> > > +\t\tANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,\n> > > +\t\tANDROID_STATISTICS_SCENE_FLICKER,\n> > > +\t};\n> > > +\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,\n> > > +\t\t\t\t  availableResultKeys);\n> > > +\n> > > +\tif (!staticMetadata_->isValid()) {\n> > > +\t\tLOG(HAL, Error) << \"Failed to construct static metadata\";\n> > > +\t\tstaticMetadata_.reset();\n> > > +\t\treturn -EINVAL;\n> > > +\t}\n> > > +\n> > > +\tif (staticMetadata_->resized()) {\n> > > +\t\tauto [entryCount, dataCount] = staticMetadata_->usage();\n> > > +\t\tLOG(HAL, Info)\n> > > +\t\t\t<< \"Static metadata resized: \" << entryCount\n> > > +\t\t\t<< \" entries and \" << dataCount << \" bytes used\";\n> > > +\t}\n> > > +\n> > > +\treturn 0;\n> > > +}\n> > > +\n> > > +/* Translate Android format code to libcamera pixel format. */\n> > > +PixelFormat CameraCapabilities::toPixelFormat(int format) const\n> > > +{\n> > > +\tauto it = formatsMap_.find(format);\n> > > +\tif (it == formatsMap_.end()) {\n> > > +\t\tLOG(HAL, Error) << \"Requested format \" << utils::hex(format)\n> > > +\t\t\t\t<< \" not supported\";\n> > > +\t\treturn PixelFormat();\n> > > +\t}\n> > > +\n> > > +\treturn it->second;\n> > > +}\n> > > +\n> > > +std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplatePreview() const\n> > > +{\n> > > +\t/*\n> > > +\t * \\todo Keep this in sync with the actual number of entries.\n> > > +\t * Currently: 20 entries, 35 bytes\n> > > +\t */\n> > > +\tauto requestTemplate = std::make_unique<CameraMetadata>(21, 36);\n> > > +\tif (!requestTemplate->isValid()) {\n> > > +\t\treturn nullptr;\n> > > +\t}\n> > > +\n> > > +\t/* Get the FPS range registered in the static metadata. */\n> > > +\tcamera_metadata_ro_entry_t entry;\n> > > +\tbool found = staticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> > > +\t\t\t\t\t       &entry);\n> > > +\tif (!found) {\n> > > +\t\tLOG(HAL, Error) << \"Cannot create capture template without FPS range\";\n> > > +\t\treturn nullptr;\n> > > +\t}\n> > > +\n> > > +\t/*\n> > > +\t * Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata\n> > > +\t * has been assembled as {{min, max} {max, max}}.\n> > > +\t */\n> > > +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> > > +\t\t\t\t  entry.data.i32, 2);\n> > > +\n> > > +\tuint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;\n> > > +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_MODE, aeMode);\n> > > +\n> > > +\tint32_t aeExposureCompensation = 0;\n> > > +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> > > +\t\t\t\t  aeExposureCompensation);\n> > > +\n> > > +\tuint8_t aePrecaptureTrigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;\n> > > +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> > > +\t\t\t\t  aePrecaptureTrigger);\n> > > +\n> > > +\tuint8_t aeLock = ANDROID_CONTROL_AE_LOCK_OFF;\n> > > +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_LOCK, aeLock);\n> > > +\n> > > +\tuint8_t aeAntibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;\n> > > +\trequestTemplate->addEntry(ANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> > > +\t\t\t\t  aeAntibandingMode);\n> > > +\n> > > +\tuint8_t afMode = ANDROID_CONTROL_AF_MODE_OFF;\n> > > +\trequestTemplate->addEntry(ANDROID_CONTROL_AF_MODE, afMode);\n> > > +\n> > > +\tuint8_t afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;\n> > > +\trequestTemplate->addEntry(ANDROID_CONTROL_AF_TRIGGER, afTrigger);\n> > > +\n> > > +\tuint8_t awbMode = ANDROID_CONTROL_AWB_MODE_AUTO;\n> > > +\trequestTemplate->addEntry(ANDROID_CONTROL_AWB_MODE, awbMode);\n> > > +\n> > > +\tuint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;\n> > > +\trequestTemplate->addEntry(ANDROID_CONTROL_AWB_LOCK, awbLock);\n> > > +\n> > > +\tuint8_t flashMode = ANDROID_FLASH_MODE_OFF;\n> > > +\trequestTemplate->addEntry(ANDROID_FLASH_MODE, flashMode);\n> > > +\n> > > +\tuint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;\n> > > +\trequestTemplate->addEntry(ANDROID_STATISTICS_FACE_DETECT_MODE,\n> > > +\t\t\t\t  faceDetectMode);\n> > > +\n> > > +\tuint8_t noiseReduction = ANDROID_NOISE_REDUCTION_MODE_OFF;\n> > > +\trequestTemplate->addEntry(ANDROID_NOISE_REDUCTION_MODE,\n> > > +\t\t\t\t  noiseReduction);\n> > > +\n> > > +\tuint8_t aberrationMode = ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF;\n> > > +\trequestTemplate->addEntry(ANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> > > +\t\t\t\t  aberrationMode);\n> > > +\n> > > +\tuint8_t controlMode = ANDROID_CONTROL_MODE_AUTO;\n> > > +\trequestTemplate->addEntry(ANDROID_CONTROL_MODE, controlMode);\n> > > +\n> > > +\tfloat lensAperture = 2.53 / 100;\n> > > +\trequestTemplate->addEntry(ANDROID_LENS_APERTURE, lensAperture);\n> > > +\n> > > +\tuint8_t opticalStabilization = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;\n> > > +\trequestTemplate->addEntry(ANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> > > +\t\t\t\t  opticalStabilization);\n> > > +\n> > > +\tuint8_t captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;\n> > > +\trequestTemplate->addEntry(ANDROID_CONTROL_CAPTURE_INTENT,\n> > > +\t\t\t\t  captureIntent);\n> > > +\n> > > +\treturn requestTemplate;\n> > > +}\n> > > +\n> > > +std::unique_ptr<CameraMetadata> CameraCapabilities::requestTemplateVideo() const\n> > > +{\n> > > +\tstd::unique_ptr<CameraMetadata> previewTemplate = requestTemplatePreview();\n> > > +\tif (!previewTemplate)\n> > > +\t\treturn nullptr;\n> > > +\n> > > +\t/*\n> > > +\t * The video template requires a fixed FPS range. Everything else\n> > > +\t * stays the same as the preview template.\n> > > +\t */\n> > > +\tcamera_metadata_ro_entry_t entry;\n> > > +\tstaticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> > > +\t\t\t\t  &entry);\n> > > +\n> > > +\t/*\n> > > +\t * Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata\n> > > +\t * has been assembled as {{min, max} {max, max}}.\n> > > +\t */\n> > > +\tpreviewTemplate->updateEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> > > +\t\t\t\t     entry.data.i32 + 2, 2);\n> > > +\n> > > +\treturn previewTemplate;\n> > > +}\n> > > diff --git a/src/android/camera_capabilities.h b/src/android/camera_capabilities.h\n> > > new file mode 100644\n> > > index 000000000000..3a427e768aff\n> > > --- /dev/null\n> > > +++ b/src/android/camera_capabilities.h\n> > > @@ -0,0 +1,64 @@\n> > > +/* SPDX-License-Identifier: LGPL-2.1-or-later */\n> > > +/*\n> > > + * Copyright (C) 2021, Google Inc.\n> > > + *\n> > > + * camera_capabilities.h - Camera static properties manager\n> > > + */\n> > > +#ifndef __ANDROID_CAMERA_CAPABILITIES_H__\n> > > +#define __ANDROID_CAMERA_CAPABILITIES_H__\n> > > +\n> > > +#include <map>\n> > > +#include <memory>\n> > > +#include <vector>\n> > > +\n> > > +#include <libcamera/camera.h>\n> > > +#include <libcamera/class.h>\n> > > +#include <libcamera/geometry.h>\n> > > +\n> > > +#include \"camera_metadata.h\"\n> > > +\n> > > +class CameraCapabilities\n> > > +{\n> > > +public:\n> > > +\tCameraCapabilities() = default;\n> > > +\n> > > +\tint initialize(std::shared_ptr<libcamera::Camera> camera,\n> > > +\t\t       int orientation, int facing);\n> > > +\n> > > +\tCameraMetadata *staticMetadata() const { return staticMetadata_.get(); }\n> > > +\tlibcamera::PixelFormat toPixelFormat(int format) const;\n> >\n> > You should include libcamera/format.h for PixelFormat.\n> \n> ack!\n> \n> > > +\tunsigned int maxJpegBufferSize() const { return maxJpegBufferSize_; }\n> > > +\n> > > +\tstd::unique_ptr<CameraMetadata> requestTemplatePreview() const;\n> > > +\tstd::unique_ptr<CameraMetadata> requestTemplateVideo() const;\n> > > +\n> > > +private:\n> > > +\tLIBCAMERA_DISABLE_COPY_AND_MOVE(CameraCapabilities)\n> > > +\n> > > +\tstruct Camera3StreamConfiguration {\n> > > +\t\tlibcamera::Size resolution;\n> > > +\t\tint androidFormat;\n> > > +\t};\n> > > +\n> > > +\tstd::vector<libcamera::Size>\n> > > +\tgetYUVResolutions(libcamera::CameraConfiguration *cameraConfig,\n> >\n> > This needs libcamera/camera.h.\n>\n> Isn't it included ?\n> \n> > > +#include <libcamera/camera.h>\n\n/me goes back to bed :-)\n\n> > > +\t\t\t  const libcamera::PixelFormat &pixelFormat,\n> > > +\t\t\t  const std::vector<libcamera::Size> &resolutions);\n> > > +\tstd::vector<libcamera::Size>\n> > > +\tgetRawResolutions(const libcamera::PixelFormat &pixelFormat);\n> > > +\tint initializeStreamConfigurations();\n> > > +\n> > > +\tint initializeStaticMetadata();\n> > > +\n> > > +\tstd::shared_ptr<libcamera::Camera> camera_;\n> > > +\n> > > +\tint facing_;\n> > > +\tint orientation_;\n> > > +\n> > > +\tstd::vector<Camera3StreamConfiguration> streamConfigurations_;\n> > > +\tstd::map<int, libcamera::PixelFormat> formatsMap_;\n> > > +\tstd::unique_ptr<CameraMetadata> staticMetadata_;\n> > > +\tunsigned int maxJpegBufferSize_;\n> > > +};\n> > > +\n> > > +#endif /* __ANDROID_CAMERA_CAPABILITIES_H__ */\n> > > diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp\n> > > index 8c71fd0675d3..4bd125d7020a 100644\n> > > --- a/src/android/camera_device.cpp\n> > > +++ b/src/android/camera_device.cpp\n> > > @@ -10,11 +10,8 @@\n> > >  #include \"camera_ops.h\"\n> > >  #include \"post_processor.h\"\n> > >\n> > > -#include <array>\n> > > -#include <cmath>\n> > >  #include <fstream>\n> > >  #include <sys/mman.h>\n> > > -#include <tuple>\n> > >  #include <unistd.h>\n> > >  #include <vector>\n> > >\n> > > @@ -23,7 +20,6 @@\n> > >  #include <libcamera/formats.h>\n> > >  #include <libcamera/property_ids.h>\n> > >\n> > > -#include \"libcamera/internal/formats.h\"\n> > >  #include \"libcamera/internal/log.h\"\n> > >  #include \"libcamera/internal/thread.h\"\n> > >  #include \"libcamera/internal/utils.h\"\n> > > @@ -36,94 +32,6 @@ LOG_DECLARE_CATEGORY(HAL)\n> > >\n> > >  namespace {\n> > >\n> > > -/*\n> > > - * \\var camera3Resolutions\n> > > - * \\brief The list of image resolutions defined as mandatory to be supported by\n> > > - * the Android Camera3 specification\n> > > - */\n> > > -const std::vector<Size> camera3Resolutions = {\n> > > -\t{ 320, 240 },\n> > > -\t{ 640, 480 },\n> > > -\t{ 1280, 720 },\n> > > -\t{ 1920, 1080 }\n> > > -};\n> > > -\n> > > -/*\n> > > - * \\struct Camera3Format\n> > > - * \\brief Data associated with an Android format identifier\n> > > - * \\var libcameraFormats List of libcamera pixel formats compatible with the\n> > > - * Android format\n> > > - * \\var name The human-readable representation of the Android format code\n> > > - */\n> > > -struct Camera3Format {\n> > > -\tstd::vector<PixelFormat> libcameraFormats;\n> > > -\tbool mandatory;\n> > > -\tconst char *name;\n> > > -};\n> > > -\n> > > -/*\n> > > - * \\var camera3FormatsMap\n> > > - * \\brief Associate Android format code with ancillary data\n> > > - */\n> > > -const std::map<int, const Camera3Format> camera3FormatsMap = {\n> > > -\t{\n> > > -\t\tHAL_PIXEL_FORMAT_BLOB, {\n> > > -\t\t\t{ formats::MJPEG },\n> > > -\t\t\ttrue,\n> > > -\t\t\t\"BLOB\"\n> > > -\t\t}\n> > > -\t}, {\n> > > -\t\tHAL_PIXEL_FORMAT_YCbCr_420_888, {\n> > > -\t\t\t{ formats::NV12, formats::NV21 },\n> > > -\t\t\ttrue,\n> > > -\t\t\t\"YCbCr_420_888\"\n> > > -\t\t}\n> > > -\t}, {\n> > > -\t\t/*\n> > > -\t\t * \\todo Translate IMPLEMENTATION_DEFINED inspecting the gralloc\n> > > -\t\t * usage flag. For now, copy the YCbCr_420 configuration.\n> > > -\t\t */\n> > > -\t\tHAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, {\n> > > -\t\t\t{ formats::NV12, formats::NV21 },\n> > > -\t\t\ttrue,\n> > > -\t\t\t\"IMPLEMENTATION_DEFINED\"\n> > > -\t\t}\n> > > -\t}, {\n> > > -\t\tHAL_PIXEL_FORMAT_RAW10, {\n> > > -\t\t\t{\n> > > -\t\t\t\tformats::SBGGR10_CSI2P,\n> > > -\t\t\t\tformats::SGBRG10_CSI2P,\n> > > -\t\t\t\tformats::SGRBG10_CSI2P,\n> > > -\t\t\t\tformats::SRGGB10_CSI2P\n> > > -\t\t\t},\n> > > -\t\t\tfalse,\n> > > -\t\t\t\"RAW10\"\n> > > -\t\t}\n> > > -\t}, {\n> > > -\t\tHAL_PIXEL_FORMAT_RAW12, {\n> > > -\t\t\t{\n> > > -\t\t\t\tformats::SBGGR12_CSI2P,\n> > > -\t\t\t\tformats::SGBRG12_CSI2P,\n> > > -\t\t\t\tformats::SGRBG12_CSI2P,\n> > > -\t\t\t\tformats::SRGGB12_CSI2P\n> > > -\t\t\t},\n> > > -\t\t\tfalse,\n> > > -\t\t\t\"RAW12\"\n> > > -\t\t}\n> > > -\t}, {\n> > > -\t\tHAL_PIXEL_FORMAT_RAW16, {\n> > > -\t\t\t{\n> > > -\t\t\t\tformats::SBGGR16,\n> > > -\t\t\t\tformats::SGBRG16,\n> > > -\t\t\t\tformats::SGRBG16,\n> > > -\t\t\t\tformats::SRGGB16\n> > > -\t\t\t},\n> > > -\t\t\tfalse,\n> > > -\t\t\t\"RAW16\"\n> > > -\t\t}\n> > > -\t},\n> > > -};\n> > > -\n> > >  /*\n> > >   * \\struct Camera3StreamConfig\n> > >   * \\brief Data to store StreamConfiguration associated with camera3_stream(s)\n> > > @@ -512,242 +420,7 @@ int CameraDevice::initialize(const CameraConfigData *cameraConfigData)\n> > >  \t\torientation_ = 0;\n> > >  \t}\n> >\n> > Shouldn't the code above be moved too ?\n> \n> It seems to me it deals with run time stream configuration, not to\n> building the static list of available camera streams like the part I\n> moved, doesn't it ?\n\nI meant the part related to orientation and location, isn't that static\n?\n\n> > >\n> > > -\t/* Acquire the camera and initialize available stream configurations. */\n> > > -\tint ret = camera_->acquire();\n> > > -\tif (ret) {\n> > > -\t\tLOG(HAL, Error) << \"Failed to temporarily acquire the camera\";\n> > > -\t\treturn ret;\n> > > -\t}\n> > > -\n> > > -\tret = initializeStreamConfigurations();\n> > > -\tcamera_->release();\n> > > -\treturn ret;\n> > > -}\n> > > -\n> > > -std::vector<Size> CameraDevice::getYUVResolutions(CameraConfiguration *cameraConfig,\n> > > -\t\t\t\t\t\t  const PixelFormat &pixelFormat,\n> > > -\t\t\t\t\t\t  const std::vector<Size> &resolutions)\n> > > -{\n> > > -\tstd::vector<Size> supportedResolutions;\n> > > -\n> > > -\tStreamConfiguration &cfg = cameraConfig->at(0);\n> > > -\tfor (const Size &res : resolutions) {\n> > > -\t\tcfg.pixelFormat = pixelFormat;\n> > > -\t\tcfg.size = res;\n> > > -\n> > > -\t\tCameraConfiguration::Status status = cameraConfig->validate();\n> > > -\t\tif (status != CameraConfiguration::Valid) {\n> > > -\t\t\tLOG(HAL, Debug) << cfg.toString() << \" not supported\";\n> > > -\t\t\tcontinue;\n> > > -\t\t}\n> > > -\n> > > -\t\tLOG(HAL, Debug) << cfg.toString() << \" supported\";\n> > > -\n> > > -\t\tsupportedResolutions.push_back(res);\n> > > -\t}\n> > > -\n> > > -\treturn supportedResolutions;\n> > > -}\n> > > -\n> > > -std::vector<Size> CameraDevice::getRawResolutions(const libcamera::PixelFormat &pixelFormat)\n> > > -{\n> > > -\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> > > -\t\tcamera_->generateConfiguration({ StreamRole::Raw });\n> > > -\tStreamConfiguration &cfg = cameraConfig->at(0);\n> > > -\tconst StreamFormats &formats = cfg.formats();\n> > > -\tstd::vector<Size> supportedResolutions = formats.sizes(pixelFormat);\n> > > -\n> > > -\treturn supportedResolutions;\n> > > -}\n> > > -\n> > > -/*\n> > > - * Initialize the format conversion map to translate from Android format\n> > > - * identifier to libcamera pixel formats and fill in the list of supported\n> > > - * stream configurations to be reported to the Android camera framework through\n> > > - * the static stream configuration metadata.\n> > > - */\n> > > -int CameraDevice::initializeStreamConfigurations()\n> > > -{\n> > > -\t/*\n> > > -\t * Get the maximum output resolutions\n> > > -\t * \\todo Get this from the camera properties once defined\n> > > -\t */\n> > > -\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> > > -\t\tcamera_->generateConfiguration({ StillCapture });\n> > > -\tif (!cameraConfig) {\n> > > -\t\tLOG(HAL, Error) << \"Failed to get maximum resolution\";\n> > > -\t\treturn -EINVAL;\n> > > -\t}\n> > > -\tStreamConfiguration &cfg = cameraConfig->at(0);\n> > > -\n> > > -\t/*\n> > > -\t * \\todo JPEG - Adjust the maximum available resolution by taking the\n> > > -\t * JPEG encoder requirements into account (alignment and aspect ratio).\n> > > -\t */\n> > > -\tconst Size maxRes = cfg.size;\n> > > -\tLOG(HAL, Debug) << \"Maximum supported resolution: \" << maxRes.toString();\n> > > -\n> > > -\t/*\n> > > -\t * Build the list of supported image resolutions.\n> > > -\t *\n> > > -\t * The resolutions listed in camera3Resolution are mandatory to be\n> > > -\t * supported, up to the camera maximum resolution.\n> > > -\t *\n> > > -\t * Augment the list by adding resolutions calculated from the camera\n> > > -\t * maximum one.\n> > > -\t */\n> > > -\tstd::vector<Size> cameraResolutions;\n> > > -\tstd::copy_if(camera3Resolutions.begin(), camera3Resolutions.end(),\n> > > -\t\t     std::back_inserter(cameraResolutions),\n> > > -\t\t     [&](const Size &res) { return res < maxRes; });\n> > > -\n> > > -\t/*\n> > > -\t * The Camera3 specification suggests adding 1/2 and 1/4 of the maximum\n> > > -\t * resolution.\n> > > -\t */\n> > > -\tfor (unsigned int divider = 2;; divider <<= 1) {\n> > > -\t\tSize derivedSize{\n> > > -\t\t\tmaxRes.width / divider,\n> > > -\t\t\tmaxRes.height / divider,\n> > > -\t\t};\n> > > -\n> > > -\t\tif (derivedSize.width < 320 ||\n> > > -\t\t    derivedSize.height < 240)\n> > > -\t\t\tbreak;\n> > > -\n> > > -\t\tcameraResolutions.push_back(derivedSize);\n> > > -\t}\n> > > -\tcameraResolutions.push_back(maxRes);\n> > > -\n> > > -\t/* Remove duplicated entries from the list of supported resolutions. */\n> > > -\tstd::sort(cameraResolutions.begin(), cameraResolutions.end());\n> > > -\tauto last = std::unique(cameraResolutions.begin(), cameraResolutions.end());\n> > > -\tcameraResolutions.erase(last, cameraResolutions.end());\n> > > -\n> > > -\t/*\n> > > -\t * Build the list of supported camera formats.\n> > > -\t *\n> > > -\t * To each Android format a list of compatible libcamera formats is\n> > > -\t * associated. The first libcamera format that tests successful is added\n> > > -\t * to the format translation map used when configuring the streams.\n> > > -\t * It is then tested against the list of supported camera resolutions to\n> > > -\t * build the stream configuration map reported through the camera static\n> > > -\t * metadata.\n> > > -\t */\n> > > -\tSize maxJpegSize;\n> > > -\tfor (const auto &format : camera3FormatsMap) {\n> > > -\t\tint androidFormat = format.first;\n> > > -\t\tconst Camera3Format &camera3Format = format.second;\n> > > -\t\tconst std::vector<PixelFormat> &libcameraFormats =\n> > > -\t\t\tcamera3Format.libcameraFormats;\n> > > -\n> > > -\t\tLOG(HAL, Debug) << \"Trying to map Android format \"\n> > > -\t\t\t\t<< camera3Format.name;\n> > > -\n> > > -\t\t/*\n> > > -\t\t * JPEG is always supported, either produced directly by the\n> > > -\t\t * camera, or encoded in the HAL.\n> > > -\t\t */\n> > > -\t\tif (androidFormat == HAL_PIXEL_FORMAT_BLOB) {\n> > > -\t\t\tformatsMap_[androidFormat] = formats::MJPEG;\n> > > -\t\t\tLOG(HAL, Debug) << \"Mapped Android format \"\n> > > -\t\t\t\t\t<< camera3Format.name << \" to \"\n> > > -\t\t\t\t\t<< formats::MJPEG.toString()\n> > > -\t\t\t\t\t<< \" (fixed mapping)\";\n> > > -\t\t\tcontinue;\n> > > -\t\t}\n> > > -\n> > > -\t\t/*\n> > > -\t\t * Test the libcamera formats that can produce images\n> > > -\t\t * compatible with the format defined by Android.\n> > > -\t\t */\n> > > -\t\tPixelFormat mappedFormat;\n> > > -\t\tfor (const PixelFormat &pixelFormat : libcameraFormats) {\n> > > -\n> > > -\t\t\tLOG(HAL, Debug) << \"Testing \" << pixelFormat.toString();\n> > > -\n> > > -\t\t\t/*\n> > > -\t\t\t * The stream configuration size can be adjusted,\n> > > -\t\t\t * not the pixel format.\n> > > -\t\t\t *\n> > > -\t\t\t * \\todo This could be simplified once all pipeline\n> > > -\t\t\t * handlers will report the StreamFormats list of\n> > > -\t\t\t * supported formats.\n> > > -\t\t\t */\n> > > -\t\t\tcfg.pixelFormat = pixelFormat;\n> > > -\n> > > -\t\t\tCameraConfiguration::Status status = cameraConfig->validate();\n> > > -\t\t\tif (status != CameraConfiguration::Invalid &&\n> > > -\t\t\t    cfg.pixelFormat == pixelFormat) {\n> > > -\t\t\t\tmappedFormat = pixelFormat;\n> > > -\t\t\t\tbreak;\n> > > -\t\t\t}\n> > > -\t\t}\n> > > -\n> > > -\t\tif (!mappedFormat.isValid()) {\n> > > -\t\t\t/* If the format is not mandatory, skip it. */\n> > > -\t\t\tif (!camera3Format.mandatory)\n> > > -\t\t\t\tcontinue;\n> > > -\n> > > -\t\t\tLOG(HAL, Error)\n> > > -\t\t\t\t<< \"Failed to map mandatory Android format \"\n> > > -\t\t\t\t<< camera3Format.name << \" (\"\n> > > -\t\t\t\t<< utils::hex(androidFormat) << \"): aborting\";\n> > > -\t\t\treturn -EINVAL;\n> > > -\t\t}\n> > > -\n> > > -\t\t/*\n> > > -\t\t * Record the mapping and then proceed to generate the\n> > > -\t\t * stream configurations map, by testing the image resolutions.\n> > > -\t\t */\n> > > -\t\tformatsMap_[androidFormat] = mappedFormat;\n> > > -\t\tLOG(HAL, Debug) << \"Mapped Android format \"\n> > > -\t\t\t\t<< camera3Format.name << \" to \"\n> > > -\t\t\t\t<< mappedFormat.toString();\n> > > -\n> > > -\t\tstd::vector<Size> resolutions;\n> > > -\t\tconst PixelFormatInfo &info = PixelFormatInfo::info(mappedFormat);\n> > > -\t\tif (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW)\n> > > -\t\t\tresolutions = getRawResolutions(mappedFormat);\n> > > -\t\telse\n> > > -\t\t\tresolutions = getYUVResolutions(cameraConfig.get(),\n> > > -\t\t\t\t\t\t\tmappedFormat,\n> > > -\t\t\t\t\t\t\tcameraResolutions);\n> > > -\n> > > -\t\tfor (const Size &res : resolutions) {\n> > > -\t\t\tstreamConfigurations_.push_back({ res, androidFormat });\n> > > -\n> > > -\t\t\t/*\n> > > -\t\t\t * If the format is HAL_PIXEL_FORMAT_YCbCr_420_888\n> > > -\t\t\t * from which JPEG is produced, add an entry for\n> > > -\t\t\t * the JPEG stream.\n> > > -\t\t\t *\n> > > -\t\t\t * \\todo Wire the JPEG encoder to query the supported\n> > > -\t\t\t * sizes provided a list of formats it can encode.\n> > > -\t\t\t *\n> > > -\t\t\t * \\todo Support JPEG streams produced by the Camera\n> > > -\t\t\t * natively.\n> > > -\t\t\t */\n> > > -\t\t\tif (androidFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {\n> > > -\t\t\t\tstreamConfigurations_.push_back(\n> > > -\t\t\t\t\t{ res, HAL_PIXEL_FORMAT_BLOB });\n> > > -\t\t\t\tmaxJpegSize = std::max(maxJpegSize, res);\n> > > -\t\t\t}\n> > > -\t\t}\n> > > -\n> > > -\t\t/*\n> > > -\t\t * \\todo Calculate the maximum JPEG buffer size by asking the\n> > > -\t\t * encoder giving the maximum frame size required.\n> > > -\t\t */\n> > > -\t\tmaxJpegBufferSize_ = maxJpegSize.width * maxJpegSize.height * 1.5;\n> > > -\t}\n> > > -\n> > > -\tLOG(HAL, Debug) << \"Collected stream configuration map: \";\n> > > -\tfor (const auto &entry : streamConfigurations_)\n> > > -\t\tLOG(HAL, Debug) << \"{ \" << entry.resolution.toString() << \" - \"\n> > > -\t\t\t\t<< utils::hex(entry.androidFormat) << \" }\";\n> > > -\n> > > -\treturn 0;\n> > > +\treturn capabilities_.initialize(camera_, orientation_, facing_);\n> > >  }\n> > >\n> > >  /*\n> > > @@ -817,802 +490,19 @@ void CameraDevice::stop()\n> > >  \tstate_ = State::Stopped;\n> > >  }\n> > >\n> > > -void CameraDevice::setCallbacks(const camera3_callback_ops_t *callbacks)\n> > > +unsigned int CameraDevice::maxJpegBufferSize() const\n> > >  {\n> > > -\tcallbacks_ = callbacks;\n> > > +\treturn capabilities_.maxJpegBufferSize();\n> > >  }\n> > >\n> > > -/*\n> > > - * Return static information for the camera.\n> > > - */\n> > > -const camera_metadata_t *CameraDevice::getStaticMetadata()\n> > > -{\n> > > -\tif (staticMetadata_)\n> > > -\t\treturn staticMetadata_->get();\n> > > -\n> > > -\tstaticMetadata_ = std::make_unique<CameraMetadata>(64, 1024);\n> > > -\tif (!staticMetadata_->isValid()) {\n> > > -\t\tLOG(HAL, Error) << \"Failed to allocate static metadata\";\n> > > -\t\tstaticMetadata_.reset();\n> > > -\t\treturn nullptr;\n> > > -\t}\n> > > -\n> > > -\tconst ControlInfoMap &controlsInfo = camera_->controls();\n> > > -\tconst ControlList &properties = camera_->properties();\n> > > -\n> > > -\t/* Color correction static metadata. */\n> > > -\t{\n> > > -\t\tstd::vector<uint8_t> data;\n> > > -\t\tdata.reserve(3);\n> > > -\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::ColorCorrectionAberrationMode);\n> > > -\t\tif (infoMap != controlsInfo.end()) {\n> > > -\t\t\tfor (const auto &value : infoMap->second.values())\n> > > -\t\t\t\tdata.push_back(value.get<int32_t>());\n> > > -\t\t} else {\n> > > -\t\t\tdata.push_back(ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF);\n> > > -\t\t}\n> > > -\t\tstaticMetadata_->addEntry(ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,\n> > > -\t\t\t\t\t  data);\n> > > -\t}\n> > > -\n> > > -\t/* Control static metadata. */\n> > > -\tstd::vector<uint8_t> aeAvailableAntiBandingModes = {\n> > > -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_OFF,\n> > > -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_50HZ,\n> > > -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_60HZ,\n> > > -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO,\n> > > -\t};\n> > > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,\n> > > -\t\t\t\t  aeAvailableAntiBandingModes);\n> > > -\n> > > -\tstd::vector<uint8_t> aeAvailableModes = {\n> > > -\t\tANDROID_CONTROL_AE_MODE_ON,\n> > > -\t};\n> > > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_MODES,\n> > > -\t\t\t\t  aeAvailableModes);\n> > > -\n> > > -\tint64_t minFrameDurationNsec = -1;\n> > > -\tint64_t maxFrameDurationNsec = -1;\n> > > -\tconst auto frameDurationsInfo = controlsInfo.find(&controls::FrameDurationLimits);\n> > > -\tif (frameDurationsInfo != controlsInfo.end()) {\n> > > -\t\tminFrameDurationNsec = frameDurationsInfo->second.min().get<int64_t>() * 1000;\n> > > -\t\tmaxFrameDurationNsec = frameDurationsInfo->second.max().get<int64_t>() * 1000;\n> > > -\n> > > -\t\t/*\n> > > -\t\t * Adjust the minimum frame duration to comply with Android\n> > > -\t\t * requirements. The camera service mandates all preview/record\n> > > -\t\t * streams to have a minimum frame duration < 33,366 milliseconds\n> > > -\t\t * (see MAX_PREVIEW_RECORD_DURATION_NS in the camera service\n> > > -\t\t * implementation).\n> > > -\t\t *\n> > > -\t\t * If we're close enough (+ 500 useconds) to that value, round\n> > > -\t\t * the minimum frame duration of the camera to an accepted\n> > > -\t\t * value.\n> > > -\t\t */\n> > > -\t\tstatic constexpr int64_t MAX_PREVIEW_RECORD_DURATION_NS = 1e9 / 29.97;\n> > > -\t\tif (minFrameDurationNsec > MAX_PREVIEW_RECORD_DURATION_NS &&\n> > > -\t\t    minFrameDurationNsec < MAX_PREVIEW_RECORD_DURATION_NS + 500000)\n> > > -\t\t\tminFrameDurationNsec = MAX_PREVIEW_RECORD_DURATION_NS - 1000;\n> > > -\n> > > -\t\t/*\n> > > -\t\t * The AE routine frame rate limits are computed using the frame\n> > > -\t\t * duration limits, as libcamera clips the AE routine to the\n> > > -\t\t * frame durations.\n> > > -\t\t */\n> > > -\t\tint32_t maxFps = std::round(1e9 / minFrameDurationNsec);\n> > > -\t\tint32_t minFps = std::round(1e9 / maxFrameDurationNsec);\n> > > -\t\tminFps = std::max(1, minFps);\n> > > -\n> > > -\t\t/*\n> > > -\t\t * Force rounding errors so that we have the proper frame\n> > > -\t\t * durations for when we reuse these variables later\n> > > -\t\t */\n> > > -\t\tminFrameDurationNsec = 1e9 / maxFps;\n> > > -\t\tmaxFrameDurationNsec = 1e9 / minFps;\n> > > -\n> > > -\t\t/*\n> > > -\t\t * Register to the camera service {min, max} and {max, max}\n> > > -\t\t * intervals as requested by the metadata documentation.\n> > > -\t\t */\n> > > -\t\tint32_t availableAeFpsTarget[] = {\n> > > -\t\t\tminFps, maxFps, maxFps, maxFps\n> > > -\t\t};\n> > > -\t\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> > > -\t\t\t\t\t  availableAeFpsTarget);\n> > > -\t}\n> > > -\n> > > -\tstd::vector<int32_t> aeCompensationRange = {\n> > > -\t\t0, 0,\n> > > -\t};\n> > > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_RANGE,\n> > > -\t\t\t\t  aeCompensationRange);\n> > > -\n> > > -\tconst camera_metadata_rational_t aeCompensationStep[] = {\n> > > -\t\t{ 0, 1 }\n> > > -\t};\n> > > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_COMPENSATION_STEP,\n> > > -\t\t\t\t  aeCompensationStep);\n> > > -\n> > > -\tstd::vector<uint8_t> availableAfModes = {\n> > > -\t\tANDROID_CONTROL_AF_MODE_OFF,\n> > > -\t};\n> > > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AF_AVAILABLE_MODES,\n> > > -\t\t\t\t  availableAfModes);\n> > > -\n> > > -\tstd::vector<uint8_t> availableEffects = {\n> > > -\t\tANDROID_CONTROL_EFFECT_MODE_OFF,\n> > > -\t};\n> > > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_EFFECTS,\n> > > -\t\t\t\t  availableEffects);\n> > > -\n> > > -\tstd::vector<uint8_t> availableSceneModes = {\n> > > -\t\tANDROID_CONTROL_SCENE_MODE_DISABLED,\n> > > -\t};\n> > > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_SCENE_MODES,\n> > > -\t\t\t\t  availableSceneModes);\n> > > -\n> > > -\tstd::vector<uint8_t> availableStabilizationModes = {\n> > > -\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE_OFF,\n> > > -\t};\n> > > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,\n> > > -\t\t\t\t  availableStabilizationModes);\n> > > -\n> > > -\t/*\n> > > -\t * \\todo Inspect the Camera capabilities to report the available\n> > > -\t * AWB modes. Default to AUTO as CTS tests require it.\n> > > -\t */\n> > > -\tstd::vector<uint8_t> availableAwbModes = {\n> > > -\t\tANDROID_CONTROL_AWB_MODE_AUTO,\n> > > -\t};\n> > > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AWB_AVAILABLE_MODES,\n> > > -\t\t\t\t  availableAwbModes);\n> > > -\n> > > -\tstd::vector<int32_t> availableMaxRegions = {\n> > > -\t\t0, 0, 0,\n> > > -\t};\n> > > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_MAX_REGIONS,\n> > > -\t\t\t\t  availableMaxRegions);\n> > > -\n> > > -\tstd::vector<uint8_t> sceneModesOverride = {\n> > > -\t\tANDROID_CONTROL_AE_MODE_ON,\n> > > -\t\tANDROID_CONTROL_AWB_MODE_AUTO,\n> > > -\t\tANDROID_CONTROL_AF_MODE_OFF,\n> > > -\t};\n> > > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_SCENE_MODE_OVERRIDES,\n> > > -\t\t\t\t  sceneModesOverride);\n> > > -\n> > > -\tuint8_t aeLockAvailable = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE;\n> > > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE,\n> > > -\t\t\t\t  aeLockAvailable);\n> > > -\n> > > -\tuint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE;\n> > > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> > > -\t\t\t\t  awbLockAvailable);\n> > > -\n> > > -\tchar availableControlModes = ANDROID_CONTROL_MODE_AUTO;\n> > > -\tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_MODES,\n> > > -\t\t\t\t  availableControlModes);\n> > > -\n> > > -\t/* JPEG static metadata. */\n> > > -\n> > > -\t/*\n> > > -\t * Create the list of supported thumbnail sizes by inspecting the\n> > > -\t * available JPEG resolutions collected in streamConfigurations_ and\n> > > -\t * generate one entry for each aspect ratio.\n> > > -\t *\n> > > -\t * The JPEG thumbnailer can freely scale, so pick an arbitrary\n> > > -\t * (160, 160) size as the bounding rectangle, which is then cropped to\n> > > -\t * the different supported aspect ratios.\n> > > -\t */\n> > > -\tconstexpr Size maxJpegThumbnail(160, 160);\n> > > -\tstd::vector<Size> thumbnailSizes;\n> > > -\tthumbnailSizes.push_back({ 0, 0 });\n> > > -\tfor (const auto &entry : streamConfigurations_) {\n> > > -\t\tif (entry.androidFormat != HAL_PIXEL_FORMAT_BLOB)\n> > > -\t\t\tcontinue;\n> > > -\n> > > -\t\tSize thumbnailSize = maxJpegThumbnail\n> > > -\t\t\t\t     .boundedToAspectRatio({ entry.resolution.width,\n> > > -\t\t\t\t\t\t\t     entry.resolution.height });\n> > > -\t\tthumbnailSizes.push_back(thumbnailSize);\n> > > -\t}\n> > > -\n> > > -\tstd::sort(thumbnailSizes.begin(), thumbnailSizes.end());\n> > > -\tauto last = std::unique(thumbnailSizes.begin(), thumbnailSizes.end());\n> > > -\tthumbnailSizes.erase(last, thumbnailSizes.end());\n> > > -\n> > > -\t/* Transform sizes in to a list of integers that can be consumed. */\n> > > -\tstd::vector<int32_t> thumbnailEntries;\n> > > -\tthumbnailEntries.reserve(thumbnailSizes.size() * 2);\n> > > -\tfor (const auto &size : thumbnailSizes) {\n> > > -\t\tthumbnailEntries.push_back(size.width);\n> > > -\t\tthumbnailEntries.push_back(size.height);\n> > > -\t}\n> > > -\tstaticMetadata_->addEntry(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,\n> > > -\t\t\t\t  thumbnailEntries);\n> > > -\n> > > -\tstaticMetadata_->addEntry(ANDROID_JPEG_MAX_SIZE, maxJpegBufferSize_);\n> > > -\n> > > -\t/* Sensor static metadata. */\n> > > -\tstd::array<int32_t, 2> pixelArraySize;\n> > > -\t{\n> > > -\t\tconst Size &size = properties.get(properties::PixelArraySize);\n> > > -\t\tpixelArraySize[0] = size.width;\n> > > -\t\tpixelArraySize[1] = size.height;\n> > > -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,\n> > > -\t\t\t\t\t  pixelArraySize);\n> > > -\t}\n> > > -\n> > > -\tif (properties.contains(properties::UnitCellSize)) {\n> > > -\t\tconst Size &cellSize = properties.get<Size>(properties::UnitCellSize);\n> > > -\t\tstd::array<float, 2> physicalSize{\n> > > -\t\t\tcellSize.width * pixelArraySize[0] / 1e6f,\n> > > -\t\t\tcellSize.height * pixelArraySize[1] / 1e6f\n> > > -\t\t};\n> > > -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_PHYSICAL_SIZE,\n> > > -\t\t\t\t\t  physicalSize);\n> > > -\t}\n> > > -\n> > > -\t{\n> > > -\t\tconst Span<const Rectangle> &rects =\n> > > -\t\t\tproperties.get(properties::PixelArrayActiveAreas);\n> > > -\t\tstd::vector<int32_t> data{\n> > > -\t\t\tstatic_cast<int32_t>(rects[0].x),\n> > > -\t\t\tstatic_cast<int32_t>(rects[0].y),\n> > > -\t\t\tstatic_cast<int32_t>(rects[0].width),\n> > > -\t\t\tstatic_cast<int32_t>(rects[0].height),\n> > > -\t\t};\n> > > -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,\n> > > -\t\t\t\t\t  data);\n> > > -\t}\n> > > -\n> > > -\tint32_t sensitivityRange[] = {\n> > > -\t\t32, 2400,\n> > > -\t};\n> > > -\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_SENSITIVITY_RANGE,\n> > > -\t\t\t\t  sensitivityRange);\n> > > -\n> > > -\t/* Report the color filter arrangement if the camera reports it. */\n> > > -\tif (properties.contains(properties::draft::ColorFilterArrangement)) {\n> > > -\t\tuint8_t filterArr = properties.get(properties::draft::ColorFilterArrangement);\n> > > -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,\n> > > -\t\t\t\t\t  filterArr);\n> > > -\t}\n> > > -\n> > > -\tconst auto &exposureInfo = controlsInfo.find(&controls::ExposureTime);\n> > > -\tif (exposureInfo != controlsInfo.end()) {\n> > > -\t\tint64_t exposureTimeRange[2] = {\n> > > -\t\t\texposureInfo->second.min().get<int32_t>() * 1000LL,\n> > > -\t\t\texposureInfo->second.max().get<int32_t>() * 1000LL,\n> > > -\t\t};\n> > > -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,\n> > > -\t\t\t\t\t  exposureTimeRange, 2);\n> > > -\t}\n> > > -\n> > > -\tstaticMetadata_->addEntry(ANDROID_SENSOR_ORIENTATION, orientation_);\n> > > -\n> > > -\tstd::vector<int32_t> testPatternModes = {\n> > > -\t\tANDROID_SENSOR_TEST_PATTERN_MODE_OFF\n> > > -\t};\n> > > -\tconst auto &testPatternsInfo =\n> > > -\t\tcontrolsInfo.find(&controls::draft::TestPatternMode);\n> > > -\tif (testPatternsInfo != controlsInfo.end()) {\n> > > -\t\tconst auto &values = testPatternsInfo->second.values();\n> > > -\t\tASSERT(!values.empty());\n> > > -\t\tfor (const auto &value : values) {\n> > > -\t\t\tswitch (value.get<int32_t>()) {\n> > > -\t\t\tcase controls::draft::TestPatternModeOff:\n> > > -\t\t\t\t/*\n> > > -\t\t\t\t * ANDROID_SENSOR_TEST_PATTERN_MODE_OFF is\n> > > -\t\t\t\t * already in testPatternModes.\n> > > -\t\t\t\t */\n> > > -\t\t\t\tbreak;\n> > > -\n> > > -\t\t\tcase controls::draft::TestPatternModeSolidColor:\n> > > -\t\t\t\ttestPatternModes.push_back(\n> > > -\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR);\n> > > -\t\t\t\tbreak;\n> > > -\n> > > -\t\t\tcase controls::draft::TestPatternModeColorBars:\n> > > -\t\t\t\ttestPatternModes.push_back(\n> > > -\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS);\n> > > -\t\t\t\tbreak;\n> > > -\n> > > -\t\t\tcase controls::draft::TestPatternModeColorBarsFadeToGray:\n> > > -\t\t\t\ttestPatternModes.push_back(\n> > > -\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_COLOR_BARS_FADE_TO_GRAY);\n> > > -\t\t\t\tbreak;\n> > > -\n> > > -\t\t\tcase controls::draft::TestPatternModePn9:\n> > > -\t\t\t\ttestPatternModes.push_back(\n> > > -\t\t\t\t\tANDROID_SENSOR_TEST_PATTERN_MODE_PN9);\n> > > -\t\t\t\tbreak;\n> > > -\n> > > -\t\t\tcase controls::draft::TestPatternModeCustom1:\n> > > -\t\t\t\t/* We don't support this yet. */\n> > > -\t\t\t\tbreak;\n> > > -\n> > > -\t\t\tdefault:\n> > > -\t\t\t\tLOG(HAL, Error) << \"Unknown test pattern mode: \"\n> > > -\t\t\t\t\t\t<< value.get<int32_t>();\n> > > -\t\t\t\tcontinue;\n> > > -\t\t\t}\n> > > -\t\t}\n> > > -\t}\n> > > -\tstaticMetadata_->addEntry(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,\n> > > -\t\t\t\t  testPatternModes);\n> > > -\n> > > -\tuint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;\n> > > -\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,\n> > > -\t\t\t\t  timestampSource);\n> > > -\n> > > -\tif (maxFrameDurationNsec > 0)\n> > > -\t\tstaticMetadata_->addEntry(ANDROID_SENSOR_INFO_MAX_FRAME_DURATION,\n> > > -\t\t\t\t\t  maxFrameDurationNsec);\n> > > -\n> > > -\t/* Statistics static metadata. */\n> > > -\tuint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;\n> > > -\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,\n> > > -\t\t\t\t  faceDetectMode);\n> > > -\n> > > -\tint32_t maxFaceCount = 0;\n> > > -\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_MAX_FACE_COUNT,\n> > > -\t\t\t\t  maxFaceCount);\n> > > -\n> > > -\t{\n> > > -\t\tstd::vector<uint8_t> data;\n> > > -\t\tdata.reserve(2);\n> > > -\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::LensShadingMapMode);\n> > > -\t\tif (infoMap != controlsInfo.end()) {\n> > > -\t\t\tfor (const auto &value : infoMap->second.values())\n> > > -\t\t\t\tdata.push_back(value.get<int32_t>());\n> > > -\t\t} else {\n> > > -\t\t\tdata.push_back(ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF);\n> > > -\t\t}\n> > > -\t\tstaticMetadata_->addEntry(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES,\n> > > -\t\t\t\t\t  data);\n> > > -\t}\n> > > -\n> > > -\t/* Sync static metadata. */\n> > > -\tint32_t maxLatency = ANDROID_SYNC_MAX_LATENCY_UNKNOWN;\n> > > -\tstaticMetadata_->addEntry(ANDROID_SYNC_MAX_LATENCY, maxLatency);\n> > > -\n> > > -\t/* Flash static metadata. */\n> > > -\tchar flashAvailable = ANDROID_FLASH_INFO_AVAILABLE_FALSE;\n> > > -\tstaticMetadata_->addEntry(ANDROID_FLASH_INFO_AVAILABLE,\n> > > -\t\t\t\t  flashAvailable);\n> > > -\n> > > -\t/* Lens static metadata. */\n> > > -\tstd::vector<float> lensApertures = {\n> > > -\t\t2.53 / 100,\n> > > -\t};\n> > > -\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_APERTURES,\n> > > -\t\t\t\t  lensApertures);\n> > > -\n> > > -\tuint8_t lensFacing;\n> > > -\tswitch (facing_) {\n> > > -\tdefault:\n> > > -\tcase CAMERA_FACING_FRONT:\n> > > -\t\tlensFacing = ANDROID_LENS_FACING_FRONT;\n> > > -\t\tbreak;\n> > > -\tcase CAMERA_FACING_BACK:\n> > > -\t\tlensFacing = ANDROID_LENS_FACING_BACK;\n> > > -\t\tbreak;\n> > > -\tcase CAMERA_FACING_EXTERNAL:\n> > > -\t\tlensFacing = ANDROID_LENS_FACING_EXTERNAL;\n> > > -\t\tbreak;\n> > > -\t}\n> > > -\tstaticMetadata_->addEntry(ANDROID_LENS_FACING, lensFacing);\n> > > -\n> > > -\tstd::vector<float> lensFocalLengths = {\n> > > -\t\t1,\n> > > -\t};\n> > > -\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,\n> > > -\t\t\t\t  lensFocalLengths);\n> > > -\n> > > -\tstd::vector<uint8_t> opticalStabilizations = {\n> > > -\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF,\n> > > -\t};\n> > > -\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,\n> > > -\t\t\t\t  opticalStabilizations);\n> > > -\n> > > -\tfloat hypeFocalDistance = 0;\n> > > -\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,\n> > > -\t\t\t\t  hypeFocalDistance);\n> > > -\n> > > -\tfloat minFocusDistance = 0;\n> > > -\tstaticMetadata_->addEntry(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,\n> > > -\t\t\t\t  minFocusDistance);\n> > > -\n> > > -\t/* Noise reduction modes. */\n> > > -\t{\n> > > -\t\tstd::vector<uint8_t> data;\n> > > -\t\tdata.reserve(5);\n> > > -\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::NoiseReductionMode);\n> > > -\t\tif (infoMap != controlsInfo.end()) {\n> > > -\t\t\tfor (const auto &value : infoMap->second.values())\n> > > -\t\t\t\tdata.push_back(value.get<int32_t>());\n> > > -\t\t} else {\n> > > -\t\t\tdata.push_back(ANDROID_NOISE_REDUCTION_MODE_OFF);\n> > > -\t\t}\n> > > -\t\tstaticMetadata_->addEntry(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,\n> > > -\t\t\t\t\t  data);\n> > > -\t}\n> > > -\n> > > -\t/* Scaler static metadata. */\n> > > -\n> > > -\t/*\n> > > -\t * \\todo The digital zoom factor is a property that depends on the\n> > > -\t * desired output configuration and the sensor frame size input to the\n> > > -\t * ISP. This information is not available to the Android HAL, not at\n> > > -\t * initialization time at least.\n> > > -\t *\n> > > -\t * As a workaround rely on pipeline handlers initializing the\n> > > -\t * ScalerCrop control with the camera default configuration and use the\n> > > -\t * maximum and minimum crop rectangles to calculate the digital zoom\n> > > -\t * factor.\n> > > -\t */\n> > > -\tfloat maxZoom = 1.0f;\n> > > -\tconst auto scalerCrop = controlsInfo.find(&controls::ScalerCrop);\n> > > -\tif (scalerCrop != controlsInfo.end()) {\n> > > -\t\tRectangle min = scalerCrop->second.min().get<Rectangle>();\n> > > -\t\tRectangle max = scalerCrop->second.max().get<Rectangle>();\n> > > -\t\tmaxZoom = std::min(1.0f * max.width / min.width,\n> > > -\t\t\t\t   1.0f * max.height / min.height);\n> > > -\t}\n> > > -\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,\n> > > -\t\t\t\t  maxZoom);\n> > > -\n> > > -\tstd::vector<uint32_t> availableStreamConfigurations;\n> > > -\tavailableStreamConfigurations.reserve(streamConfigurations_.size() * 4);\n> > > -\tfor (const auto &entry : streamConfigurations_) {\n> > > -\t\tavailableStreamConfigurations.push_back(entry.androidFormat);\n> > > -\t\tavailableStreamConfigurations.push_back(entry.resolution.width);\n> > > -\t\tavailableStreamConfigurations.push_back(entry.resolution.height);\n> > > -\t\tavailableStreamConfigurations.push_back(\n> > > -\t\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT);\n> > > -\t}\n> > > -\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,\n> > > -\t\t\t\t  availableStreamConfigurations);\n> > > -\n> > > -\tstd::vector<int64_t> availableStallDurations = {\n> > > -\t\tANDROID_SCALER_AVAILABLE_FORMATS_BLOB, 2560, 1920, 33333333,\n> > > -\t};\n> > > -\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS,\n> > > -\t\t\t\t  availableStallDurations);\n> > > -\n> > > -\t/* Use the minimum frame duration for all the YUV/RGB formats. */\n> > > -\tif (minFrameDurationNsec > 0) {\n> > > -\t\tstd::vector<int64_t> minFrameDurations;\n> > > -\t\tminFrameDurations.reserve(streamConfigurations_.size() * 4);\n> > > -\t\tfor (const auto &entry : streamConfigurations_) {\n> > > -\t\t\tminFrameDurations.push_back(entry.androidFormat);\n> > > -\t\t\tminFrameDurations.push_back(entry.resolution.width);\n> > > -\t\t\tminFrameDurations.push_back(entry.resolution.height);\n> > > -\t\t\tminFrameDurations.push_back(minFrameDurationNsec);\n> > > -\t\t}\n> > > -\t\tstaticMetadata_->addEntry(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,\n> > > -\t\t\t\t\t  minFrameDurations);\n> > > -\t}\n> > > -\n> > > -\tuint8_t croppingType = ANDROID_SCALER_CROPPING_TYPE_CENTER_ONLY;\n> > > -\tstaticMetadata_->addEntry(ANDROID_SCALER_CROPPING_TYPE, croppingType);\n> > > -\n> > > -\t/* Info static metadata. */\n> > > -\tuint8_t supportedHWLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;\n> > > -\tstaticMetadata_->addEntry(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,\n> > > -\t\t\t\t  supportedHWLevel);\n> > > -\n> > > -\t/* Request static metadata. */\n> > > -\tint32_t partialResultCount = 1;\n> > > -\tstaticMetadata_->addEntry(ANDROID_REQUEST_PARTIAL_RESULT_COUNT,\n> > > -\t\t\t\t  partialResultCount);\n> > > -\n> > > -\t{\n> > > -\t\t/* Default the value to 2 if not reported by the camera. */\n> > > -\t\tuint8_t maxPipelineDepth = 2;\n> > > -\t\tconst auto &infoMap = controlsInfo.find(&controls::draft::PipelineDepth);\n> > > -\t\tif (infoMap != controlsInfo.end())\n> > > -\t\t\tmaxPipelineDepth = infoMap->second.max().get<int32_t>();\n> > > -\t\tstaticMetadata_->addEntry(ANDROID_REQUEST_PIPELINE_MAX_DEPTH,\n> > > -\t\t\t\t\t  maxPipelineDepth);\n> > > -\t}\n> > > -\n> > > -\t/* LIMITED does not support reprocessing. */\n> > > -\tuint32_t maxNumInputStreams = 0;\n> > > -\tstaticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,\n> > > -\t\t\t\t  maxNumInputStreams);\n> > > -\n> > > -\tstd::vector<uint8_t> availableCapabilities = {\n> > > -\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,\n> > > -\t};\n> > > -\n> > > -\t/* Report if camera supports RAW. */\n> > > -\tbool rawStreamAvailable = false;\n> > > -\tstd::unique_ptr<CameraConfiguration> cameraConfig =\n> > > -\t\tcamera_->generateConfiguration({ StreamRole::Raw });\n> > > -\tif (cameraConfig && !cameraConfig->empty()) {\n> > > -\t\tconst PixelFormatInfo &info =\n> > > -\t\t\tPixelFormatInfo::info(cameraConfig->at(0).pixelFormat);\n> > > -\t\t/* Only advertise RAW support if RAW16 is possible. */\n> > > -\t\tif (info.colourEncoding == PixelFormatInfo::ColourEncodingRAW &&\n> > > -\t\t    info.bitsPerPixel == 16) {\n> > > -\t\t\trawStreamAvailable = true;\n> > > -\t\t\tavailableCapabilities.push_back(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);\n> > > -\t\t}\n> > > -\t}\n> > > -\n> > > -\t/* Number of { RAW, YUV, JPEG } supported output streams */\n> > > -\tint32_t numOutStreams[] = { rawStreamAvailable, 2, 1 };\n> > > -\tstaticMetadata_->addEntry(ANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,\n> > > -\t\t\t\t  numOutStreams);\n> > > -\n> > > -\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CAPABILITIES,\n> > > -\t\t\t\t  availableCapabilities);\n> > > -\n> > > -\tstd::vector<int32_t> availableCharacteristicsKeys = {\n> > > -\t\tANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,\n> > > -\t\tANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,\n> > > -\t\tANDROID_CONTROL_AE_AVAILABLE_MODES,\n> > > -\t\tANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> > > -\t\tANDROID_CONTROL_AE_COMPENSATION_RANGE,\n> > > -\t\tANDROID_CONTROL_AE_COMPENSATION_STEP,\n> > > -\t\tANDROID_CONTROL_AE_LOCK_AVAILABLE,\n> > > -\t\tANDROID_CONTROL_AF_AVAILABLE_MODES,\n> > > -\t\tANDROID_CONTROL_AVAILABLE_EFFECTS,\n> > > -\t\tANDROID_CONTROL_AVAILABLE_MODES,\n> > > -\t\tANDROID_CONTROL_AVAILABLE_SCENE_MODES,\n> > > -\t\tANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,\n> > > -\t\tANDROID_CONTROL_AWB_AVAILABLE_MODES,\n> > > -\t\tANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n> > > -\t\tANDROID_CONTROL_MAX_REGIONS,\n> > > -\t\tANDROID_CONTROL_SCENE_MODE_OVERRIDES,\n> > > -\t\tANDROID_FLASH_INFO_AVAILABLE,\n> > > -\t\tANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,\n> > > -\t\tANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES,\n> > > -\t\tANDROID_JPEG_MAX_SIZE,\n> > > -\t\tANDROID_LENS_FACING,\n> > > -\t\tANDROID_LENS_INFO_AVAILABLE_APERTURES,\n> > > -\t\tANDROID_LENS_INFO_AVAILABLE_FOCAL_LENGTHS,\n> > > -\t\tANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,\n> > > -\t\tANDROID_LENS_INFO_HYPERFOCAL_DISTANCE,\n> > > -\t\tANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE,\n> > > -\t\tANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,\n> > > -\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES,\n> > > -\t\tANDROID_REQUEST_MAX_NUM_INPUT_STREAMS,\n> > > -\t\tANDROID_REQUEST_MAX_NUM_OUTPUT_STREAMS,\n> > > -\t\tANDROID_REQUEST_PARTIAL_RESULT_COUNT,\n> > > -\t\tANDROID_REQUEST_PIPELINE_MAX_DEPTH,\n> > > -\t\tANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM,\n> > > -\t\tANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS,\n> > > -\t\tANDROID_SCALER_AVAILABLE_STALL_DURATIONS,\n> > > -\t\tANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,\n> > > -\t\tANDROID_SCALER_CROPPING_TYPE,\n> > > -\t\tANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES,\n> > > -\t\tANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,\n> > > -\t\tANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT,\n> > > -\t\tANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE,\n> > > -\t\tANDROID_SENSOR_INFO_MAX_FRAME_DURATION,\n> > > -\t\tANDROID_SENSOR_INFO_PHYSICAL_SIZE,\n> > > -\t\tANDROID_SENSOR_INFO_PIXEL_ARRAY_SIZE,\n> > > -\t\tANDROID_SENSOR_INFO_SENSITIVITY_RANGE,\n> > > -\t\tANDROID_SENSOR_INFO_TIMESTAMP_SOURCE,\n> > > -\t\tANDROID_SENSOR_ORIENTATION,\n> > > -\t\tANDROID_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES,\n> > > -\t\tANDROID_STATISTICS_INFO_MAX_FACE_COUNT,\n> > > -\t\tANDROID_SYNC_MAX_LATENCY,\n> > > -\t};\n> > > -\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS,\n> > > -\t\t\t\t  availableCharacteristicsKeys);\n> > > -\n> > > -\tstd::vector<int32_t> availableRequestKeys = {\n> > > -\t\tANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> > > -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> > > -\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> > > -\t\tANDROID_CONTROL_AE_LOCK,\n> > > -\t\tANDROID_CONTROL_AE_MODE,\n> > > -\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> > > -\t\tANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> > > -\t\tANDROID_CONTROL_AF_MODE,\n> > > -\t\tANDROID_CONTROL_AF_TRIGGER,\n> > > -\t\tANDROID_CONTROL_AWB_LOCK,\n> > > -\t\tANDROID_CONTROL_AWB_MODE,\n> > > -\t\tANDROID_CONTROL_CAPTURE_INTENT,\n> > > -\t\tANDROID_CONTROL_EFFECT_MODE,\n> > > -\t\tANDROID_CONTROL_MODE,\n> > > -\t\tANDROID_CONTROL_SCENE_MODE,\n> > > -\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE,\n> > > -\t\tANDROID_FLASH_MODE,\n> > > -\t\tANDROID_JPEG_ORIENTATION,\n> > > -\t\tANDROID_JPEG_QUALITY,\n> > > -\t\tANDROID_JPEG_THUMBNAIL_QUALITY,\n> > > -\t\tANDROID_JPEG_THUMBNAIL_SIZE,\n> > > -\t\tANDROID_LENS_APERTURE,\n> > > -\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> > > -\t\tANDROID_NOISE_REDUCTION_MODE,\n> > > -\t\tANDROID_SCALER_CROP_REGION,\n> > > -\t\tANDROID_STATISTICS_FACE_DETECT_MODE\n> > > -\t};\n> > > -\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS,\n> > > -\t\t\t\t  availableRequestKeys);\n> > > -\n> > > -\tstd::vector<int32_t> availableResultKeys = {\n> > > -\t\tANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> > > -\t\tANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> > > -\t\tANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> > > -\t\tANDROID_CONTROL_AE_LOCK,\n> > > -\t\tANDROID_CONTROL_AE_MODE,\n> > > -\t\tANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> > > -\t\tANDROID_CONTROL_AE_STATE,\n> > > -\t\tANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> > > -\t\tANDROID_CONTROL_AF_MODE,\n> > > -\t\tANDROID_CONTROL_AF_STATE,\n> > > -\t\tANDROID_CONTROL_AF_TRIGGER,\n> > > -\t\tANDROID_CONTROL_AWB_LOCK,\n> > > -\t\tANDROID_CONTROL_AWB_MODE,\n> > > -\t\tANDROID_CONTROL_AWB_STATE,\n> > > -\t\tANDROID_CONTROL_CAPTURE_INTENT,\n> > > -\t\tANDROID_CONTROL_EFFECT_MODE,\n> > > -\t\tANDROID_CONTROL_MODE,\n> > > -\t\tANDROID_CONTROL_SCENE_MODE,\n> > > -\t\tANDROID_CONTROL_VIDEO_STABILIZATION_MODE,\n> > > -\t\tANDROID_FLASH_MODE,\n> > > -\t\tANDROID_FLASH_STATE,\n> > > -\t\tANDROID_JPEG_GPS_COORDINATES,\n> > > -\t\tANDROID_JPEG_GPS_PROCESSING_METHOD,\n> > > -\t\tANDROID_JPEG_GPS_TIMESTAMP,\n> > > -\t\tANDROID_JPEG_ORIENTATION,\n> > > -\t\tANDROID_JPEG_QUALITY,\n> > > -\t\tANDROID_JPEG_SIZE,\n> > > -\t\tANDROID_JPEG_THUMBNAIL_QUALITY,\n> > > -\t\tANDROID_JPEG_THUMBNAIL_SIZE,\n> > > -\t\tANDROID_LENS_APERTURE,\n> > > -\t\tANDROID_LENS_FOCAL_LENGTH,\n> > > -\t\tANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> > > -\t\tANDROID_LENS_STATE,\n> > > -\t\tANDROID_NOISE_REDUCTION_MODE,\n> > > -\t\tANDROID_REQUEST_PIPELINE_DEPTH,\n> > > -\t\tANDROID_SCALER_CROP_REGION,\n> > > -\t\tANDROID_SENSOR_EXPOSURE_TIME,\n> > > -\t\tANDROID_SENSOR_FRAME_DURATION,\n> > > -\t\tANDROID_SENSOR_ROLLING_SHUTTER_SKEW,\n> > > -\t\tANDROID_SENSOR_TEST_PATTERN_MODE,\n> > > -\t\tANDROID_SENSOR_TIMESTAMP,\n> > > -\t\tANDROID_STATISTICS_FACE_DETECT_MODE,\n> > > -\t\tANDROID_STATISTICS_LENS_SHADING_MAP_MODE,\n> > > -\t\tANDROID_STATISTICS_HOT_PIXEL_MAP_MODE,\n> > > -\t\tANDROID_STATISTICS_SCENE_FLICKER,\n> > > -\t};\n> > > -\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_RESULT_KEYS,\n> > > -\t\t\t\t  availableResultKeys);\n> > > -\n> > > -\tif (!staticMetadata_->isValid()) {\n> > > -\t\tLOG(HAL, Error) << \"Failed to construct static metadata\";\n> > > -\t\tstaticMetadata_.reset();\n> > > -\t\treturn nullptr;\n> > > -\t}\n> > > -\n> > > -\tif (staticMetadata_->resized()) {\n> > > -\t\tauto [entryCount, dataCount] = staticMetadata_->usage();\n> > > -\t\tLOG(HAL, Info)\n> > > -\t\t\t<< \"Static metadata resized: \" << entryCount\n> > > -\t\t\t<< \" entries and \" << dataCount << \" bytes used\";\n> > > -\t}\n> > > -\n> > > -\treturn staticMetadata_->get();\n> > > -}\n> > > -\n> > > -std::unique_ptr<CameraMetadata> CameraDevice::requestTemplatePreview()\n> > > +void CameraDevice::setCallbacks(const camera3_callback_ops_t *callbacks)\n> > >  {\n> > > -\t/*\n> > > -\t * \\todo Keep this in sync with the actual number of entries.\n> > > -\t * Currently: 20 entries, 35 bytes\n> > > -\t */\n> > > -\tauto requestTemplate = std::make_unique<CameraMetadata>(21, 36);\n> > > -\tif (!requestTemplate->isValid()) {\n> > > -\t\treturn nullptr;\n> > > -\t}\n> > > -\n> > > -\t/* Get the FPS range registered in the static metadata. */\n> > > -\tcamera_metadata_ro_entry_t entry;\n> > > -\tbool found = staticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> > > -\t\t\t\t\t       &entry);\n> > > -\tif (!found) {\n> > > -\t\tLOG(HAL, Error) << \"Cannot create capture template without FPS range\";\n> > > -\t\treturn nullptr;\n> > > -\t}\n> > > -\n> > > -\t/*\n> > > -\t * Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata\n> > > -\t * has been assembled as {{min, max} {max, max}}.\n> > > -\t */\n> > > -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> > > -\t\t\t\t  entry.data.i32, 2);\n> > > -\n> > > -\tuint8_t aeMode = ANDROID_CONTROL_AE_MODE_ON;\n> > > -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_MODE, aeMode);\n> > > -\n> > > -\tint32_t aeExposureCompensation = 0;\n> > > -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION,\n> > > -\t\t\t\t  aeExposureCompensation);\n> > > -\n> > > -\tuint8_t aePrecaptureTrigger = ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER_IDLE;\n> > > -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER,\n> > > -\t\t\t\t  aePrecaptureTrigger);\n> > > -\n> > > -\tuint8_t aeLock = ANDROID_CONTROL_AE_LOCK_OFF;\n> > > -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_LOCK, aeLock);\n> > > -\n> > > -\tuint8_t aeAntibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;\n> > > -\trequestTemplate->addEntry(ANDROID_CONTROL_AE_ANTIBANDING_MODE,\n> > > -\t\t\t\t  aeAntibandingMode);\n> > > -\n> > > -\tuint8_t afMode = ANDROID_CONTROL_AF_MODE_OFF;\n> > > -\trequestTemplate->addEntry(ANDROID_CONTROL_AF_MODE, afMode);\n> > > -\n> > > -\tuint8_t afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;\n> > > -\trequestTemplate->addEntry(ANDROID_CONTROL_AF_TRIGGER, afTrigger);\n> > > -\n> > > -\tuint8_t awbMode = ANDROID_CONTROL_AWB_MODE_AUTO;\n> > > -\trequestTemplate->addEntry(ANDROID_CONTROL_AWB_MODE, awbMode);\n> > > -\n> > > -\tuint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;\n> > > -\trequestTemplate->addEntry(ANDROID_CONTROL_AWB_LOCK, awbLock);\n> > > -\n> > > -\tuint8_t flashMode = ANDROID_FLASH_MODE_OFF;\n> > > -\trequestTemplate->addEntry(ANDROID_FLASH_MODE, flashMode);\n> > > -\n> > > -\tuint8_t faceDetectMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;\n> > > -\trequestTemplate->addEntry(ANDROID_STATISTICS_FACE_DETECT_MODE,\n> > > -\t\t\t\t  faceDetectMode);\n> > > -\n> > > -\tuint8_t noiseReduction = ANDROID_NOISE_REDUCTION_MODE_OFF;\n> > > -\trequestTemplate->addEntry(ANDROID_NOISE_REDUCTION_MODE,\n> > > -\t\t\t\t  noiseReduction);\n> > > -\n> > > -\tuint8_t aberrationMode = ANDROID_COLOR_CORRECTION_ABERRATION_MODE_OFF;\n> > > -\trequestTemplate->addEntry(ANDROID_COLOR_CORRECTION_ABERRATION_MODE,\n> > > -\t\t\t\t  aberrationMode);\n> > > -\n> > > -\tuint8_t controlMode = ANDROID_CONTROL_MODE_AUTO;\n> > > -\trequestTemplate->addEntry(ANDROID_CONTROL_MODE, controlMode);\n> > > -\n> > > -\tfloat lensAperture = 2.53 / 100;\n> > > -\trequestTemplate->addEntry(ANDROID_LENS_APERTURE, lensAperture);\n> > > -\n> > > -\tuint8_t opticalStabilization = ANDROID_LENS_OPTICAL_STABILIZATION_MODE_OFF;\n> > > -\trequestTemplate->addEntry(ANDROID_LENS_OPTICAL_STABILIZATION_MODE,\n> > > -\t\t\t\t  opticalStabilization);\n> > > -\n> > > -\tuint8_t captureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;\n> > > -\trequestTemplate->addEntry(ANDROID_CONTROL_CAPTURE_INTENT,\n> > > -\t\t\t\t  captureIntent);\n> > > -\n> > > -\treturn requestTemplate;\n> > > +\tcallbacks_ = callbacks;\n> > >  }\n> > >\n> > > -std::unique_ptr<CameraMetadata> CameraDevice::requestTemplateVideo()\n> > > +const camera_metadata_t *CameraDevice::getStaticMetadata()\n> > >  {\n> > > -\tstd::unique_ptr<CameraMetadata> previewTemplate = requestTemplatePreview();\n> > > -\tif (!previewTemplate)\n> > > -\t\treturn nullptr;\n> > > -\n> > > -\t/*\n> > > -\t * The video template requires a fixed FPS range. Everything else\n> > > -\t * stays the same as the preview template.\n> > > -\t */\n> > > -\tcamera_metadata_ro_entry_t entry;\n> > > -\tstaticMetadata_->getEntry(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES,\n> > > -\t\t\t\t  &entry);\n> > > -\n> > > -\t/*\n> > > -\t * Assume the AE_AVAILABLE_TARGET_FPS_RANGE static metadata\n> > > -\t * has been assembled as {{min, max} {max, max}}.\n> > > -\t */\n> > > -\tpreviewTemplate->updateEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE,\n> > > -\t\t\t\t     entry.data.i32 + 2, 2);\n> > > -\n> > > -\treturn previewTemplate;\n> > > +\treturn capabilities_.staticMetadata()->get();\n> > >  }\n> > >\n> > >  /*\n> > > @@ -1630,7 +520,7 @@ const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type)\n> > >  \tswitch (type) {\n> > >  \tcase CAMERA3_TEMPLATE_PREVIEW:\n> > >  \t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;\n> > > -\t\trequestTemplate = requestTemplatePreview();\n> > > +\t\trequestTemplate = capabilities_.requestTemplatePreview();\n> > >  \t\tbreak;\n> > >  \tcase CAMERA3_TEMPLATE_STILL_CAPTURE:\n> > >  \t\t/*\n> > > @@ -1638,15 +528,15 @@ const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type)\n> > >  \t\t * for the torch mode we currently do not support.\n> > >  \t\t */\n> > >  \t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE;\n> > > -\t\trequestTemplate = requestTemplatePreview();\n> > > +\t\trequestTemplate = capabilities_.requestTemplatePreview();\n> > >  \t\tbreak;\n> > >  \tcase CAMERA3_TEMPLATE_VIDEO_RECORD:\n> > >  \t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_RECORD;\n> > > -\t\trequestTemplate = requestTemplateVideo();\n> > > +\t\trequestTemplate = capabilities_.requestTemplateVideo();\n> > >  \t\tbreak;\n> > >  \tcase CAMERA3_TEMPLATE_VIDEO_SNAPSHOT:\n> > >  \t\tcaptureIntent = ANDROID_CONTROL_CAPTURE_INTENT_VIDEO_SNAPSHOT;\n> > > -\t\trequestTemplate = requestTemplateVideo();\n> > > +\t\trequestTemplate = capabilities_.requestTemplateVideo();\n> > >  \t\tbreak;\n> > >  \t/* \\todo Implement templates generation for the remaining use cases. */\n> > >  \tcase CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG:\n> > > @@ -1668,19 +558,6 @@ const camera_metadata_t *CameraDevice::constructDefaultRequestSettings(int type)\n> > >  \treturn requestTemplates_[type]->get();\n> > >  }\n> > >\n> > > -PixelFormat CameraDevice::toPixelFormat(int format) const\n> > > -{\n> > > -\t/* Translate Android format code to libcamera pixel format. */\n> > > -\tauto it = formatsMap_.find(format);\n> > > -\tif (it == formatsMap_.end()) {\n> > > -\t\tLOG(HAL, Error) << \"Requested format \" << utils::hex(format)\n> > > -\t\t\t\t<< \" not supported\";\n> > > -\t\treturn PixelFormat();\n> > > -\t}\n> > > -\n> > > -\treturn it->second;\n> > > -}\n> > > -\n> > >  /*\n> > >   * Inspect the stream_list to produce a list of StreamConfiguration to\n> > >   * be use to configure the Camera.\n> > > @@ -1727,7 +604,7 @@ int CameraDevice::configureStreams(camera3_stream_configuration_t *stream_list)\n> > >  \t\tcamera3_stream_t *stream = stream_list->streams[i];\n> > >  \t\tSize size(stream->width, stream->height);\n> > >\n> > > -\t\tPixelFormat format = toPixelFormat(stream->format);\n> > > +\t\tPixelFormat format = capabilities_.toPixelFormat(stream->format);\n> > >\n> > >  \t\tLOG(HAL, Info) << \"Stream #\" << i\n> > >  \t\t\t       << \", direction: \" << stream->stream_type\n> > > diff --git a/src/android/camera_device.h b/src/android/camera_device.h\n> > > index 4aadb27c562c..090fe28a551e 100644\n> > > --- a/src/android/camera_device.h\n> > > +++ b/src/android/camera_device.h\n> > > @@ -10,14 +10,12 @@\n> > >  #include <map>\n> > >  #include <memory>\n> > >  #include <mutex>\n> > > -#include <tuple>\n> > >  #include <vector>\n> > >\n> > >  #include <hardware/camera3.h>\n> > >\n> > >  #include <libcamera/buffer.h>\n> > >  #include <libcamera/camera.h>\n> > > -#include <libcamera/geometry.h>\n> > >  #include <libcamera/request.h>\n> > >  #include <libcamera/stream.h>\n> > >\n> > > @@ -26,6 +24,7 @@\n> > >  #include \"libcamera/internal/message.h\"\n> > >  #include \"libcamera/internal/thread.h\"\n> > >\n> > > +#include \"camera_capabilities.h\"\n> > >  #include \"camera_metadata.h\"\n> > >  #include \"camera_stream.h\"\n> > >  #include \"camera_worker.h\"\n> > > @@ -57,7 +56,7 @@ public:\n> > >  \tconst std::string &model() const { return model_; }\n> > >  \tint facing() const { return facing_; }\n> > >  \tint orientation() const { return orientation_; }\n> > > -\tunsigned int maxJpegBufferSize() const { return maxJpegBufferSize_; }\n> > > +\tunsigned int maxJpegBufferSize() const;\n> > >\n> > >  \tvoid setCallbacks(const camera3_callback_ops_t *callbacks);\n> > >  \tconst camera_metadata_t *getStaticMetadata();\n> > > @@ -86,11 +85,6 @@ private:\n> > >  \t\tstd::unique_ptr<CaptureRequest> request_;\n> > >  \t};\n> > >\n> > > -\tstruct Camera3StreamConfiguration {\n> > > -\t\tlibcamera::Size resolution;\n> > > -\t\tint androidFormat;\n> > > -\t};\n> > > -\n> > >  \tenum class State {\n> > >  \t\tStopped,\n> > >  \t\tFlushing,\n> > > @@ -99,22 +93,11 @@ private:\n> > >\n> > >  \tvoid stop();\n> > >\n> > > -\tint initializeStreamConfigurations();\n> > > -\tstd::vector<libcamera::Size>\n> > > -\tgetYUVResolutions(libcamera::CameraConfiguration *cameraConfig,\n> > > -\t\t\t  const libcamera::PixelFormat &pixelFormat,\n> > > -\t\t\t  const std::vector<libcamera::Size> &resolutions);\n> > > -\tstd::vector<libcamera::Size>\n> > > -\tgetRawResolutions(const libcamera::PixelFormat &pixelFormat);\n> > > -\n> > >  \tlibcamera::FrameBuffer *createFrameBuffer(const buffer_handle_t camera3buffer);\n> > >  \tvoid abortRequest(camera3_capture_request_t *request);\n> > >  \tvoid notifyShutter(uint32_t frameNumber, uint64_t timestamp);\n> > >  \tvoid notifyError(uint32_t frameNumber, camera3_stream_t *stream,\n> > >  \t\t\t camera3_error_msg_code code);\n> > > -\tstd::unique_ptr<CameraMetadata> requestTemplatePreview();\n> > > -\tstd::unique_ptr<CameraMetadata> requestTemplateVideo();\n> > > -\tlibcamera::PixelFormat toPixelFormat(int format) const;\n> > >  \tint processControls(Camera3RequestDescriptor *descriptor);\n> > >  \tstd::unique_ptr<CameraMetadata> getResultMetadata(\n> > >  \t\tconst Camera3RequestDescriptor &descriptor) const;\n> > > @@ -129,13 +112,11 @@ private:\n> > >\n> > >  \tstd::shared_ptr<libcamera::Camera> camera_;\n> > >  \tstd::unique_ptr<libcamera::CameraConfiguration> config_;\n> > > +\tCameraCapabilities capabilities_;\n> > >\n> > > -\tstd::unique_ptr<CameraMetadata> staticMetadata_;\n> > >  \tstd::map<unsigned int, std::unique_ptr<CameraMetadata>> requestTemplates_;\n> > >  \tconst camera3_callback_ops_t *callbacks_;\n> > >\n> > > -\tstd::vector<Camera3StreamConfiguration> streamConfigurations_;\n> > > -\tstd::map<int, libcamera::PixelFormat> formatsMap_;\n> > >  \tstd::vector<CameraStream> streams_;\n> > >\n> > >  \tlibcamera::Mutex descriptorsMutex_; /* Protects descriptors_. */\n> > > @@ -147,8 +128,6 @@ private:\n> > >  \tint facing_;\n> > >  \tint orientation_;\n> > >\n> > > -\tunsigned int maxJpegBufferSize_;\n> > > -\n> > >  \tCameraMetadata lastSettings_;\n> > >  };\n> > >\n> > > diff --git a/src/android/meson.build b/src/android/meson.build\n> > > index 3893e5b5b832..e093aa2ec565 100644\n> > > --- a/src/android/meson.build\n> > > +++ b/src/android/meson.build\n> > > @@ -45,6 +45,7 @@ subdir('cros')\n> > >  android_hal_sources = files([\n> > >      'camera3_hal.cpp',\n> > >      'camera_hal_manager.cpp',\n> > > +    'camera_capabilities.cpp',\n> >\n> > While at it, could you sort this alphabetically ?\n> \n> Sure, maybe in a patch before this one.\n\nWorks for me, should be easy to merge :-)\n\n> > >      'camera_device.cpp',\n> > >      'camera_hal_config.cpp',\n> > >      'camera_metadata.cpp',","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 43F05BE58C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 21 Jun 2021 14:07:07 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id A18C56893C;\n\tMon, 21 Jun 2021 16:07:06 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 64F8D60295\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 21 Jun 2021 16:07:05 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id A76CF5C75;\n\tMon, 21 Jun 2021 16:07:04 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"quI7diT+\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1624284425;\n\tbh=yAoaME148OQoAYxVQ3jnNZbPXo3jWntNYx9083mlwWo=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=quI7diT+02GyMj7VrpyXfxpbh/XdnjsacHqb61iqugV7xsu/ZJ+eYn+RDIVvD4HAB\n\tLQAIpCLs7EBpkt8gyq4L6gvkgLiPWoKEind3C6Pq+BJWwMnXHSUs5LRDOAl+9U/YD4\n\tDRRuMWjAOy9dPjHIGv04KmWylNsqxCKfGio8dHPw=","Date":"Mon, 21 Jun 2021 17:06:38 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Message-ID":"<YNCc7twXlDjkEYn9@pendragon.ideasonboard.com>","References":"<20210619105151.20012-1-jacopo@jmondi.org>\n\t<20210619105151.20012-2-jacopo@jmondi.org>\n\t<YM6V63Kmy3/2zU/Y@pendragon.ideasonboard.com>\n\t<20210621135345.a3gug5ei6zxqjnif@uno.localdomain>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20210621135345.a3gug5ei6zxqjnif@uno.localdomain>","Subject":"Re: [libcamera-devel] [RFC 1/1] android: Introduce\n\tCameraCapabilties class","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":17664,"web_url":"https://patchwork.libcamera.org/comment/17664/","msgid":"<20210621141308.vznfeejhymcdl7vm@uno.localdomain>","date":"2021-06-21T14:13:08","subject":"Re: [libcamera-devel] [RFC 1/1] android: Introduce\n\tCameraCapabilties class","submitter":{"id":3,"url":"https://patchwork.libcamera.org/api/people/3/","name":"Jacopo Mondi","email":"jacopo@jmondi.org"},"content":"Hi Laurent,\n\nOn Mon, Jun 21, 2021 at 05:06:38PM +0300, Laurent Pinchart wrote:\n> Hi Jacopo,\n>\n> On Mon, Jun 21, 2021 at 03:53:45PM +0200, Jacopo Mondi wrote:\n\n[big snip]\n\n> > > >  /*\n> > > >   * \\struct Camera3StreamConfig\n> > > >   * \\brief Data to store StreamConfiguration associated with camera3_stream(s)\n> > > > @@ -512,242 +420,7 @@ int CameraDevice::initialize(const CameraConfigData *cameraConfigData)\n> > > >  \t\torientation_ = 0;\n> > > >  \t}\n> > >\n> > > Shouldn't the code above be moved too ?\n> >\n> > It seems to me it deals with run time stream configuration, not to\n> > building the static list of available camera streams like the part I\n> > moved, doesn't it ?\n>\n> I meant the part related to orientation and location, isn't that static\n> ?\n\nAh sorry, didn't get it.\nI considered that, but that would have required moving the\nconfiguration file parsing to the capabilities class, and what's will\nbe in the configuration file is still little bit still in flux\n\nAlso, the CameraDevice::initialize() would then be just a call to\ncapabilties_.initialize().\n\nWhat do you think ?","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id BBEE5C3218\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 21 Jun 2021 14:12:22 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 408BF60296;\n\tMon, 21 Jun 2021 16:12:22 +0200 (CEST)","from relay11.mail.gandi.net (relay11.mail.gandi.net\n\t[217.70.178.231])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id DE0C160295\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 21 Jun 2021 16:12:20 +0200 (CEST)","(Authenticated sender: jacopo@jmondi.org)\n\tby relay11.mail.gandi.net (Postfix) with ESMTPSA id 2838D10000B;\n\tMon, 21 Jun 2021 14:12:19 +0000 (UTC)"],"Date":"Mon, 21 Jun 2021 16:13:08 +0200","From":"Jacopo Mondi <jacopo@jmondi.org>","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Message-ID":"<20210621141308.vznfeejhymcdl7vm@uno.localdomain>","References":"<20210619105151.20012-1-jacopo@jmondi.org>\n\t<20210619105151.20012-2-jacopo@jmondi.org>\n\t<YM6V63Kmy3/2zU/Y@pendragon.ideasonboard.com>\n\t<20210621135345.a3gug5ei6zxqjnif@uno.localdomain>\n\t<YNCc7twXlDjkEYn9@pendragon.ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<YNCc7twXlDjkEYn9@pendragon.ideasonboard.com>","Subject":"Re: [libcamera-devel] [RFC 1/1] android: Introduce\n\tCameraCapabilties class","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":17665,"web_url":"https://patchwork.libcamera.org/comment/17665/","msgid":"<YNCe5cQeJQ2Y8mNg@pendragon.ideasonboard.com>","date":"2021-06-21T14:15:01","subject":"Re: [libcamera-devel] [RFC 1/1] android: Introduce\n\tCameraCapabilties class","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"Hi Jacopo,\n\nOn Mon, Jun 21, 2021 at 04:13:08PM +0200, Jacopo Mondi wrote:\n> On Mon, Jun 21, 2021 at 05:06:38PM +0300, Laurent Pinchart wrote:\n> > On Mon, Jun 21, 2021 at 03:53:45PM +0200, Jacopo Mondi wrote:\n> \n> [big snip]\n> \n> > > > >  /*\n> > > > >   * \\struct Camera3StreamConfig\n> > > > >   * \\brief Data to store StreamConfiguration associated with camera3_stream(s)\n> > > > > @@ -512,242 +420,7 @@ int CameraDevice::initialize(const CameraConfigData *cameraConfigData)\n> > > > >  \t\torientation_ = 0;\n> > > > >  \t}\n> > > >\n> > > > Shouldn't the code above be moved too ?\n> > >\n> > > It seems to me it deals with run time stream configuration, not to\n> > > building the static list of available camera streams like the part I\n> > > moved, doesn't it ?\n> >\n> > I meant the part related to orientation and location, isn't that static\n> > ?\n> \n> Ah sorry, didn't get it.\n> I considered that, but that would have required moving the\n> configuration file parsing to the capabilities class, and what's will\n> be in the configuration file is still little bit still in flux\n> \n> Also, the CameraDevice::initialize() would then be just a call to\n> capabilties_.initialize().\n> \n> What do you think ?\n\nWhatever you think is best. This is a good first step in any case, and\nI'm sure we'll continue refactoring the code.","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 4C3ADBE58C\n\tfor <parsemail@patchwork.libcamera.org>;\n\tMon, 21 Jun 2021 14:15:30 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id AE4906893A;\n\tMon, 21 Jun 2021 16:15:29 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 4F54760295\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tMon, 21 Jun 2021 16:15:28 +0200 (CEST)","from pendragon.ideasonboard.com (62-78-145-57.bb.dnainternet.fi\n\t[62.78.145.57])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id CAC035D6B;\n\tMon, 21 Jun 2021 16:15:27 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"UGNiZt+T\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1624284928;\n\tbh=qxYLHE/iM0/eGIu90gy80H/1HqdWbg8NmUt1lm9DSKM=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=UGNiZt+TZdHpxwYU8L8l+SB2JguLT6+sGXn591URNMbAalH0B54O/33slFElnaPYi\n\t+QGzfFy5XBxxI3kMSeOUzUA1iBuWP/8EdRRo+WLxH6TW4KdjdIgGMOuJirXOJnkgdJ\n\tNQmGuTcZQPKOyRbTvMVqRDiK6lZR+7oSL4EW7SG4=","Date":"Mon, 21 Jun 2021 17:15:01 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Jacopo Mondi <jacopo@jmondi.org>","Message-ID":"<YNCe5cQeJQ2Y8mNg@pendragon.ideasonboard.com>","References":"<20210619105151.20012-1-jacopo@jmondi.org>\n\t<20210619105151.20012-2-jacopo@jmondi.org>\n\t<YM6V63Kmy3/2zU/Y@pendragon.ideasonboard.com>\n\t<20210621135345.a3gug5ei6zxqjnif@uno.localdomain>\n\t<YNCc7twXlDjkEYn9@pendragon.ideasonboard.com>\n\t<20210621141308.vznfeejhymcdl7vm@uno.localdomain>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","In-Reply-To":"<20210621141308.vznfeejhymcdl7vm@uno.localdomain>","Subject":"Re: [libcamera-devel] [RFC 1/1] android: Introduce\n\tCameraCapabilties class","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Cc":"libcamera-devel@lists.libcamera.org","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]