[libcamera-devel] [RFC PATCH] wip: android: capabilities: Capability detection by population
paul.elder at ideasonboard.com
paul.elder at ideasonboard.com
Fri Jul 9 13:34:46 CEST 2021
Hello everyone,
On Fri, Jul 09, 2021 at 08:28:14PM +0900, Paul Elder wrote:
> Implement capability and hardware level detection based on the static
> metadata that has been set, instead of disabling them as requirements
> are not met. This results in cleaner code where the static metadata is
> set.
>
> Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
>
> ---
> This currently does not work as the ControlInfo constructor for Spans is
> broken. This is more of an RFC for Jacopo to check that this is the
> direction that he wants.
>
> Clearly this is not meant to be merged, as the actual capability
> requirements are not fully specified yet. Plus they belong in separate
> patches anyway.
>
> This patch does not apply either, as it depends on many unreleased
> patches.
> ---
> src/android/camera_capabilities.cpp | 219 ++++++++++++++++++++--------
> 1 file changed, 157 insertions(+), 62 deletions(-)
>
> diff --git a/src/android/camera_capabilities.cpp b/src/android/camera_capabilities.cpp
> index 83c7f0d0..ceb5cfe8 100644
> --- a/src/android/camera_capabilities.cpp
> +++ b/src/android/camera_capabilities.cpp
> @@ -262,6 +262,149 @@ std::vector<T> setMetadata(CameraMetadata *metadata, uint32_t tag,
> return ret;
> }
>
> +
> +template<typename T>
> +bool metadataContains(camera_metadata_ro_entry_t &entry, T value);
> +
> +template<>
> +bool metadataContains<uint8_t>(camera_metadata_ro_entry_t &entry, uint8_t value)
> +{
> + for (unsigned int i = 0; i < entry.count; i++)
> + if (entry.data.u8[i] == value)
> + return true;
> +
> + return false;
> +}
> +
> +bool validateManualSensorCapability(CameraMetadata *staticMetadata)
> +{
> + camera_metadata_ro_entry_t entry;
> + bool found;
> +
> + found = staticMetadata->getEntry(ANDROID_CONTROL_AE_AVAILABLE_MODES,
> + &entry);
> + if (!found || !metadataContains<uint8_t>(entry, ANDROID_CONTROL_AE_MODE_OFF)) {
> + LOG(HAL, Info)
> + << "Missing AE mode off: "
> + << (found ? "not supported" : "not found");
> + return false;
> + }
> +
> + found = staticMetadata->getEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE,
> + &entry);
> + if (!found || !(*entry.data.u8 == ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE)) {
> + LOG(HAL, Info) << "Missing AE lock";
> + return false;
> + }
> +
> + found = staticMetadata->getEntry(ANDROID_EDGE_AVAILABLE_EDGE_MODES,
> + &entry);
> + if (!found) {
> + LOG(HAL, Info) << "Missing edge modes";
> + return false;
> + }
> +
> + return true;
> +}
> +
> +bool validateManualPostProcessingCapability(CameraMetadata *staticMetadata)
> +{
> + camera_metadata_ro_entry_t entry;
> + bool found;
> +
> + found = staticMetadata->getEntry(ANDROID_CONTROL_AWB_AVAILABLE_MODES,
> + &entry);
> + if (!found || !metadataContains<uint8_t>(entry, ANDROID_CONTROL_AWB_MODE_OFF)) {
> + LOG(HAL, Info) << "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)) {
> + LOG(HAL, Info) << "Missing AWB lock";
> + return false;
> + }
> +
> + return true;
> +}
> +
> +bool validateBurstCaptureCapability(CameraMetadata *staticMetadata)
> +{
> + camera_metadata_ro_entry_t entry;
> + bool found;
> +
> + found = staticMetadata->getEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE,
> + &entry);
> + if (!found || !(*entry.data.u8 == ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE)) {
> + LOG(HAL, Info) << "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) << "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)
> + << "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>
> +computeCapabilities(CameraMetadata *staticMetadata,
> + std::set<camera_metadata_enum_android_request_available_capabilities> &existingCaps)
> +{
> + std::set<camera_metadata_enum_android_request_available_capabilities>
> + capabilities = existingCaps;
> +
> + 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);
> +
> + return capabilities;
> +}
> +
> +camera_metadata_enum_android_info_supported_hardware_level
> +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;
> +
> + return hwLevel;
> +}
> +
> } /* namespace */
>
> int CameraCapabilities::initialize(std::shared_ptr<libcamera::Camera> camera,
> @@ -655,17 +798,7 @@ int CameraCapabilities::initializeStaticMetadata()
> };
>
> std::set<camera_metadata_enum_android_request_available_capabilities>
> - capabilities = {
> - ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,
> - ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR,
> - ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING,
> - ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE,
> - };
> -
> - std::set<camera_metadata_enum_android_info_supported_hardware_level>
> - hwLevels = {
> - ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL,
> - };
> + capabilities = {};
>
> /* Color correction static metadata. */
> {
> @@ -692,19 +825,12 @@ int CameraCapabilities::initializeStaticMetadata()
> staticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,
> aeAvailableAntiBandingModes);
>
> - std::vector<uint8_t> aeModes = setMetadata<uint8_t, bool>(
> + setMetadata<uint8_t, bool>(
> staticMetadata_.get(),
> ANDROID_CONTROL_AE_AVAILABLE_MODES,
> controlsInfo, &controls::AeEnable,
> { ANDROID_CONTROL_AE_MODE_ON });
>
> - if (std::find(aeModes.begin(), aeModes.end(),
> - ANDROID_CONTROL_AE_MODE_OFF) == aeModes.end()) {
> - LOG(HAL, Info) << "AE cannot be turned off";
> - hwLevels.erase(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL);
> - capabilities.erase(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR);
> - }
> -
> int64_t minFrameDurationNsec = -1;
> int64_t maxFrameDurationNsec = -1;
> const auto frameDurationsInfo = controlsInfo.find(&controls::FrameDurationLimits);
> @@ -791,17 +917,11 @@ int CameraCapabilities::initializeStaticMetadata()
> staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,
> availableStabilizationModes);
>
> - std::vector<uint8_t> awbModes = setMetadata<uint8_t, int32_t>(
> + setMetadata<uint8_t, int32_t>(
> staticMetadata_.get(),
> ANDROID_CONTROL_AWB_AVAILABLE_MODES,
> controlsInfo, &controls::AwbMode,
> { ANDROID_CONTROL_AWB_MODE_AUTO });
> - if (std::find(awbModes.begin(), awbModes.end(),
> - ANDROID_CONTROL_AWB_MODE_OFF) == awbModes.end()) {
> - LOG(HAL, Info) << "AWB cannot be turned off";
> - hwLevels.erase(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL);
> - capabilities.erase(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING);
> - }
>
> std::vector<int32_t> availableMaxRegions = {
> 0, 0, 0,
> @@ -817,29 +937,19 @@ int CameraCapabilities::initializeStaticMetadata()
> staticMetadata_->addEntry(ANDROID_CONTROL_SCENE_MODE_OVERRIDES,
> sceneModesOverride);
>
> - uint8_t aeLockAvailable = setMetadata<uint8_t, bool>(
> + setMetadata<uint8_t, bool>(
> staticMetadata_.get(),
> ANDROID_CONTROL_AE_LOCK_AVAILABLE,
> controlsInfo, &controls::AeLock,
> ControlRange::Max,
> ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE);
> - if (aeLockAvailable != ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE) {
> - LOG(HAL, Info) << "AE lock is unavailable";
> - capabilities.erase(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE);
> - capabilities.erase(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR);
> - }
>
> - uint8_t awbLockAvailable = setMetadata<uint8_t, bool>(
> + setMetadata<uint8_t, bool>(
> staticMetadata_.get(),
> ANDROID_CONTROL_AWB_LOCK_AVAILABLE,
> controlsInfo, &controls::AwbLock,
> ControlRange::Max,
> ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE);
> - if (awbLockAvailable != ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE) {
> - LOG(HAL, Info) << "AWB lock is unavailable";
> - capabilities.erase(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE);
> - capabilities.erase(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING);
> - }
>
> char availableControlModes = ANDROID_CONTROL_MODE_AUTO;
> staticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_MODES,
> @@ -859,10 +969,6 @@ int CameraCapabilities::initializeStaticMetadata()
> availableCharacteristicsKeys_.insert(ANDROID_EDGE_AVAILABLE_EDGE_MODES);
> availableRequestKeys_.insert(ANDROID_EDGE_MODE);
> availableResultKeys_.insert(ANDROID_EDGE_MODE);
> - } else {
> - LOG(HAL, Info) << "Edge mode unavailable";
> - hwLevels.erase(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL);
> - capabilities.erase(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR);
> }
>
> /* JPEG static metadata. */
> @@ -1046,17 +1152,11 @@ int CameraCapabilities::initializeStaticMetadata()
> }
>
> /* Sync static metadata. */
> - int32_t maxLatency = setMetadata<int32_t, int32_t>(
> + setMetadata<int32_t, int32_t>(
> staticMetadata_.get(), ANDROID_SYNC_MAX_LATENCY,
> controlsInfo, &controls::draft::MaxLatency,
> ControlRange::Def,
> ANDROID_SYNC_MAX_LATENCY_UNKNOWN);
> - LOG(HAL, Info) << "Max sync latency is " << maxLatency;
> - /* CTS allows a sync latency of up to 4 for burst capture capability */
> - if (maxLatency < 0 || 4 < maxLatency)
> - capabilities.erase(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE);
> - if (maxLatency != 0)
> - hwLevels.erase(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL);
>
> /* Flash static metadata. */
> char flashAvailable = ANDROID_FLASH_INFO_AVAILABLE_FALSE;
> @@ -1220,19 +1320,14 @@ int CameraCapabilities::initializeStaticMetadata()
> numOutStreams);
>
> /* Check capabilities */
> - std::vector<uint8_t> availableCapabilities(capabilities.begin(),
> - capabilities.end());
> - staticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CAPABILITIES,
> - availableCapabilities);
> -
> - uint8_t hwLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
> - if (capabilities.count(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR) &&
> - capabilities.count(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING) &&
> - capabilities.count(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE) &&
> - hwLevels.count(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL))
> - hwLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL;
> - staticMetadata_->addEntry(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,
> - hwLevel);
> + capabilities = computeCapabilities(staticMetadata_.get(), capabilities);
Just to clarify, this is here because above this we have:
/* 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;
capabilities.insert(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_RAW);
}
}
There's no way to capture this information in the static metadata
otherwise, and I don't think it's a good idea to feed arbitrary
variables into the capabilities gatherer, since at that point we might
as well keep the method that I had earlier (which has the benefit of not
having to walk the static metadata again after setting it, but hey, a
multiple of linear time is still linear time :D).
So yeah, we allow static metadata setters to directly set the
capabilities if it alone is sufficient and necessary to determine some
capability.
Paul
> + 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: "
> --
> 2.27.0
>
More information about the libcamera-devel
mailing list