[libcamera-devel] [PATCH 2/2] android: Introduce CameraCapabilties class

Hirokazu Honda hiroh at chromium.org
Wed Jun 23 05:25:01 CEST 2021


Hi Jacopo,

On Tue, Jun 22, 2021 at 4:40 PM Jacopo Mondi <jacopo at jmondi.org> wrote:
>
> Hi Hiro,
>
> On Tue, Jun 22, 2021 at 10:34:27AM +0900, Hirokazu Honda wrote:
> > Hi Jacopo, thank you for the patch.
> >
> > I failed to apply the patch on the top of the latest tree to review.
> > Could you tell me the parent commit which I can apply this patch?
>
> weird, I just applied these two patches cleanly on the latest
> master which for me is
> 969da3189439 ("libcamera: utils: Support systems that lack secure_getenv and issetugid"
>

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

Since the code is copied as-is,
Reviewed-by: Hirokazu Honda <hiroh at chromium.org>

Although stylecheck script complains some part of code, do you think fixing it?
-Hiro
> > > --
> > > 2.31.1
> > >
> > >


More information about the libcamera-devel mailing list