[libcamera-devel] [RFC PATCH v4 05/21] android: Add infrastructure for determining capabilities and hardware level
paul.elder at ideasonboard.com
paul.elder at ideasonboard.com
Mon Jul 19 12:22:54 CEST 2021
Hi Jacopo,
On Mon, Jul 19, 2021 at 02:48:04PM +0900, paul.elder at ideasonboard.com wrote:
> Hi Jacopo,
>
> On Sat, Jul 17, 2021 at 12:11:55PM +0200, Jacopo Mondi wrote:
> > Hi Paul,
> >
> > On Fri, Jul 16, 2021 at 07:56:15PM +0900, Paul Elder wrote:
> > > Add the infrastructure for checking and reporting capabilities. Use
> > > these capabilities to determine the hardware level as well.
> > >
> > > Bug: https://bugs.libcamera.org/show_bug.cgi?id=55
> > > Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
> > >
> > > ---
> > > Changes in v5:
> > > - change the whole thing to turn on capabilities after they are all
> > > confirmed, instead of disabling them as conditions are not met
> > >
> > > Changes in v4:
> > > - rebase on camera capabilities refactoring
> > > - switch to std::set from std::map
> > > - make hwlevel similar to capabilities
> > >
> > > Changes in v3:
> > > - fix some compiler errors
> > > - go ahead and initialize the capabilities to true, update the commit
> > > message accordingly
> > >
> > > Changes in v2:
> > > - add a flag for FULL, since there are a few requirements that are not
> > > obtained from capabilities alone
> > > - add burst capture capability, since that is required for FULL as well
> > > ---
> > > src/android/camera_capabilities.cpp | 172 +++++++++++++++++++++++++---
> > > src/android/camera_capabilities.h | 13 +++
> > > 2 files changed, 170 insertions(+), 15 deletions(-)
> > >
> > > diff --git a/src/android/camera_capabilities.cpp b/src/android/camera_capabilities.cpp
> > > index 9e2714f1..be55db88 100644
> > > --- a/src/android/camera_capabilities.cpp
> > > +++ b/src/android/camera_capabilities.cpp
> > > @@ -9,6 +9,7 @@
> > >
> > > #include <array>
> > > #include <cmath>
> > > +#include <map>
> > >
> > > #include <hardware/camera3.h>
> > >
> > > @@ -114,8 +115,148 @@ const std::map<int, const Camera3Format> camera3FormatsMap = {
> > > },
> > > };
> > >
> > > +const std::map<camera_metadata_enum_android_info_supported_hardware_level, std::string>
> > > +hwLevelStrings = {
> > > + { ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED, "LIMITED" },
> > > + { ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL, "FULL" },
> > > + { ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY, "LEGACY" },
> > > + { ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_3, "LEVEL_3" },
> > > + { ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL, "EXTERNAL" },
> > > +};
> > > +
> > > } /* namespace */
> > >
> > > +bool CameraCapabilities::validateManualSensorCapability(CameraMetadata *staticMetadata)
> > > +{
> > > + camera_metadata_ro_entry_t entry;
> > > + bool found;
> > > +
> > > + const char *noMode = "Manual sensor capability unavailable: ";
> > > +
> > > + if (!(found = staticMetadata->entryContains<uint8_t>(ANDROID_CONTROL_AE_AVAILABLE_MODES,
> > > + ANDROID_CONTROL_AE_MODE_OFF))) {
> > > + LOG(HAL, Info)
> > > + << noMode << "missing AE mode off: "
> > > + << (found ? "not supported" : "not found");
> >
> > You don't get here if (found) :)
> >
> > > + return false;
> > > + }
> > > +
> > > + found = staticMetadata->getEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE,
> > > + &entry);
> > > + if (!found || !(*entry.data.u8 == ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE)) {
> >
> > Can't this just be entryContains() ?
>
> Entry contains is if the the entry is a list of items. Here (and below)
> the entry is a single item, so we can't use entryContains(). It's also
> not worth a helper since it's just "does the value equal X?".
>
> >
> > > + LOG(HAL, Info) << noMode << "missing AE lock";
> > > + return false;
> > > + }
> > > +
> > > + return true;
> > > +}
> > > +
> > > +bool CameraCapabilities::validateManualPostProcessingCapability(CameraMetadata *staticMetadata)
> > > +{
> > > + camera_metadata_ro_entry_t entry;
> > > + bool found;
> > > +
> > > + const char *noMode = "Manual post processing capability unavailable: ";
> > > +
> > > + if (!staticMetadata->entryContains<uint8_t>(ANDROID_CONTROL_AWB_AVAILABLE_MODES,
> > > + ANDROID_CONTROL_AWB_MODE_OFF)) {
> > > + LOG(HAL, Info) << noMode << "missing AWB mode off";
> > > + return false;
> > > + }
> > > +
> > > + found = staticMetadata->getEntry(ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
> > > + &entry);
> > > + if (!found || !(*entry.data.u8 == ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE)) {
> >
> > same question, can this just be entryContains() ?
> >
> > > + LOG(HAL, Info) << noMode << "missing AWB lock";
> > > + return false;
> > > + }
> > > +
> > > + return true;
> > > +}
> > > +
> > > +bool CameraCapabilities::validateBurstCaptureCapability(CameraMetadata *staticMetadata)
> > > +{
> > > + camera_metadata_ro_entry_t entry;
> > > + bool found;
> > > +
> > > + const char *noMode = "Burst capture capability unavailable: ";
> > > +
> > > + found = staticMetadata->getEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE,
> > > + &entry);
> > > + if (!found || !(*entry.data.u8 == ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE)) {
> >
> > ditto, but I suspect I'm missing something as this is a recurring
> > pattern :)
> >
> > > + LOG(HAL, Info) << noMode << "missing AE lock";
> > > + return false;
> > > + }
> > > +
> > > + found = staticMetadata->getEntry(ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
> > > + &entry);
> > > + if (!found || !(*entry.data.u8 == ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE)) {
> > > + LOG(HAL, Info) << noMode << "missing AWB lock";
> > > + return false;
> > > + }
> > > +
> > > + found = staticMetadata->getEntry(ANDROID_SYNC_MAX_LATENCY, &entry);
> > > + if (!found || *entry.data.i32 < 0 || 4 < *entry.data.i32) {
> > > + LOG(HAL, Info)
> > > + << noMode << "max sync latency is "
> > > + << (found ? std::to_string(*entry.data.i32) : "not present");
> > > + return false;
> > > + }
> > > +
> > > + return true;
> > > +}
> > > +
> > > +std::set<camera_metadata_enum_android_request_available_capabilities>
> > > +CameraCapabilities::computeCapabilities(CameraMetadata *staticMetadata,
> > > + std::set<camera_metadata_enum_android_request_available_capabilities> &existingCaps)
> > > +{
> > > + std::set<camera_metadata_enum_android_request_available_capabilities>
> > > + capabilities = existingCaps;
> >
> > Can't you just add values to existingCaps ?
>
> Oh I guess I can.
>
> >
> > > +
> > > + capabilities.insert(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
> > > +
> > > + if (validateManualSensorCapability(staticMetadata))
> > > + capabilities.insert(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR);
> > > +
> > > + if (validateManualPostProcessingCapability(staticMetadata))
> > > + capabilities.insert(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING);
> > > +
> > > + if (validateBurstCaptureCapability(staticMetadata))
> > > + capabilities.insert(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE);
> > > +
> > > + if (rawStreamAvailable_)
> > > + capabilities.insert(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);
> > > +
> > > + return capabilities;
> > > +}
> > > +
> > > +camera_metadata_enum_android_info_supported_hardware_level
> > > +CameraCapabilities::computeHwLevel(CameraMetadata *staticMetadata,
> > > + std::set<camera_metadata_enum_android_request_available_capabilities> capabilities)
> > > +{
> > > + camera_metadata_ro_entry_t entry;
> > > + bool found;
> > > + camera_metadata_enum_android_info_supported_hardware_level
> > > + hwLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL;
> > > +
> > > + if (!capabilities.count(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR))
> > > + hwLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
> > > +
> > > + if (!capabilities.count(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING))
> > > + hwLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
> > > +
> > > + if (!capabilities.count(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE))
> > > + hwLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
> > > +
> > > + found = staticMetadata->getEntry(ANDROID_SYNC_MAX_LATENCY, &entry);
> > > + if (!found || *entry.data.i32 != 0)
> > > + hwLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
> > > +
> > > + hwLevel_ = hwLevel;
> > > +
> > > + return hwLevel;
> > > +}
> > > +
> > > int CameraCapabilities::initialize(std::shared_ptr<libcamera::Camera> camera,
> > > int orientation, int facing)
> > > {
> > > @@ -382,6 +523,9 @@ int CameraCapabilities::initializeStaticMetadata()
> > > const ControlInfoMap &controlsInfo = camera_->controls();
> > > const ControlList &properties = camera_->properties();
> > >
> > > + std::set<camera_metadata_enum_android_request_available_capabilities>
> > > + capabilities = {};
> > > +
> > > /* Color correction static metadata. */
> > > {
> > > std::vector<uint8_t> data;
> > > @@ -840,11 +984,6 @@ int CameraCapabilities::initializeStaticMetadata()
> > > 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,
> > > @@ -865,21 +1004,24 @@ int CameraCapabilities::initializeStaticMetadata()
> > > 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. */
> > > - if (rawStreamAvailable_)
> > > - 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);
> > > + /* Check capabilities */
> > > + capabilities = computeCapabilities(staticMetadata_.get(), capabilities);
> >
> > Can you declate capabilities here ? It is not used before.
>
> Oh, right.
>
> > Also, what the puropse of 'existingCaps' in computeCapabilities() if
> > it's empty ? Can you just return a vector to avoid the below
Oh, this was from before your raw capability patch. I had the raw
capability checker add the capability to the set before passing it in. I
guess we can remove existingCaps now that we don't need it anymore.
Paul
> > conversion from set to vec ?
>
> I guess we can return a vector. But we'd still have a conversion, it'll
> just be in computeCapabilities() instead of out.
>
> >
> > I like the overall direction :)
>
> >
> > > + std::vector<camera_metadata_enum_android_request_available_capabilities>
> > > + capsVec = std::vector<camera_metadata_enum_android_request_available_capabilities>(capabilities.begin(), capabilities.end());
> > > + staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, capsVec);
> > > +
> > > + camera_metadata_enum_android_info_supported_hardware_level hwLevel =
> > > + computeHwLevel(staticMetadata_.get(), capabilities);
> > > + staticMetadata_->addEntry(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, hwLevel);
> > > +
> > > + LOG(HAL, Info)
> > > + << "Hardware level: "
> > > + << hwLevelStrings.find((camera_metadata_enum_android_info_supported_hardware_level)hwLevel)->second;
> > >
> > > std::vector<int32_t> availableCharacteristicsKeys = {
> > > ANDROID_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES,
> > > diff --git a/src/android/camera_capabilities.h b/src/android/camera_capabilities.h
> > > index 42a976d3..38ee97d0 100644
> > > --- a/src/android/camera_capabilities.h
> > > +++ b/src/android/camera_capabilities.h
> > > @@ -42,6 +42,18 @@ private:
> > > int androidFormat;
> > > };
> > >
> > > + bool validateManualSensorCapability(CameraMetadata *staticMetadata);
> > > + bool validateManualPostProcessingCapability(CameraMetadata *staticMetadata);
> > > + bool validateBurstCaptureCapability(CameraMetadata *staticMetadata);
> > > +
> > > + std::set<camera_metadata_enum_android_request_available_capabilities>
> > > + computeCapabilities(CameraMetadata *staticMetadata,
> > > + std::set<camera_metadata_enum_android_request_available_capabilities> &existingCaps);
> > > +
> > > + camera_metadata_enum_android_info_supported_hardware_level
> > > + computeHwLevel(CameraMetadata *staticMetadata,
> > > + std::set<camera_metadata_enum_android_request_available_capabilities> capabilities);
> > > +
> > > std::vector<libcamera::Size>
> > > initializeYUVResolutions(const libcamera::PixelFormat &pixelFormat,
> > > const std::vector<libcamera::Size> &resolutions);
> > > @@ -56,6 +68,7 @@ private:
> > > int facing_;
> > > int orientation_;
> > > bool rawStreamAvailable_;
> > > + camera_metadata_enum_android_info_supported_hardware_level hwLevel_;
> > >
> > > std::vector<Camera3StreamConfiguration> streamConfigurations_;
> > > std::map<int, libcamera::PixelFormat> formatsMap_;
> > > --
> > > 2.27.0
> > >
More information about the libcamera-devel
mailing list