[libcamera-devel,RFC,v4,05/21] android: Add infrastructure for determining capabilities and hardware level
diff mbox series

Message ID 20210716105631.158153-6-paul.elder@ideasonboard.com
State Superseded
Headers show
Series
  • Preliminary FULL plumbing
Related show

Commit Message

Paul Elder July 16, 2021, 10:56 a.m. UTC
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@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(-)

Comments

Jacopo Mondi July 17, 2021, 10:11 a.m. UTC | #1
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@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() ?

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

> +
> +	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.
Also, what the puropse of 'existingCaps' in computeCapabilities() if
it's empty ? Can you just return a vector to avoid the below
conversion from set to vec ?

I like the overall direction :)

Thanks
  j

> +	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
>
Paul Elder July 19, 2021, 5:48 a.m. UTC | #2
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@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
> 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 :)


Thanks,

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: "
> > +		<< 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
> >
Paul Elder July 19, 2021, 10:22 a.m. UTC | #3
Hi Jacopo,

On Mon, Jul 19, 2021 at 02:48:04PM +0900, paul.elder@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@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
> > >

Patch
diff mbox series

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");
+		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) << 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)) {
+		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)) {
+		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;
+
+	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);
+	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_;