{"id":12880,"url":"https://patchwork.libcamera.org/api/patches/12880/?format=json","web_url":"https://patchwork.libcamera.org/patch/12880/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20210709112814.87917-1-paul.elder@ideasonboard.com>","date":"2021-07-09T11:28:14","name":"[libcamera-devel,RFC] wip: android: capabilities: Capability detection by population","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"89cc22b4b79c1055a40a9e6128364208fb90307c","submitter":{"id":17,"url":"https://patchwork.libcamera.org/api/people/17/?format=json","name":"Paul Elder","email":"paul.elder@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/12880/mbox/","series":[{"id":2221,"url":"https://patchwork.libcamera.org/api/series/2221/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=2221","date":"2021-07-09T11:28:14","name":"[libcamera-devel,RFC] wip: android: capabilities: Capability detection by population","version":1,"mbox":"https://patchwork.libcamera.org/series/2221/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/12880/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/12880/checks/","tags":{},"headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id E1BF2C3224\n\tfor <parsemail@patchwork.libcamera.org>;\n\tFri,  9 Jul 2021 11:28:38 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 381286851B;\n\tFri,  9 Jul 2021 13:28:38 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id C0FEF605AC\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tFri,  9 Jul 2021 13:28:36 +0200 (CEST)","from pyrite.rasen.tech (unknown\n\t[IPv6:2400:4051:61:600:2c71:1b79:d06d:5032])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id C5990E7;\n\tFri,  9 Jul 2021 13:28:34 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com;\n\tdkim=fail reason=\"signature verification failed\" (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"f6G62OCp\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1625830116;\n\tbh=OMhVPC/24Cu6gjOCcFbc1tDprSFQoCdC7zGANkkjfk0=;\n\th=From:To:Cc:Subject:Date:From;\n\tb=f6G62OCpDdA9lBSx5HHcyKUjSUwmc8TtFqQabDno8T7+1fkLLp1DWZ5vWDXNrkfmr\n\tBiIT4hAwhjJj7CGp3KKAydiUBC8RZlxuHAaFFRIxSf7V9jYVHSNrQSyyxeQG9aBz4E\n\t1bU7I29brG1yZqbGFwUZQdsTDBk7gpuSgz7Fco14=","From":"Paul Elder <paul.elder@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Date":"Fri,  9 Jul 2021 20:28:14 +0900","Message-Id":"<20210709112814.87917-1-paul.elder@ideasonboard.com>","X-Mailer":"git-send-email 2.27.0","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit","Subject":"[libcamera-devel] [RFC PATCH] wip: android: capabilities:\n\tCapability detection by population","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"},"content":"Implement capability and hardware level detection based on the static\nmetadata that has been set, instead of disabling them as requirements\nare not met. This results in cleaner code where the static metadata is\nset.\n\nSigned-off-by: Paul Elder <paul.elder@ideasonboard.com>\n\n---\nThis currently does not work as the ControlInfo constructor for Spans is\nbroken. This is more of an RFC for Jacopo to check that this is the\ndirection that he wants.\n\nClearly this is not meant to be merged, as the actual capability\nrequirements are not fully specified yet. Plus they belong in separate\npatches anyway.\n\nThis patch does not apply either, as it depends on many unreleased\npatches.\n---\n src/android/camera_capabilities.cpp | 219 ++++++++++++++++++++--------\n 1 file changed, 157 insertions(+), 62 deletions(-)","diff":"diff --git a/src/android/camera_capabilities.cpp b/src/android/camera_capabilities.cpp\nindex 83c7f0d0..ceb5cfe8 100644\n--- a/src/android/camera_capabilities.cpp\n+++ b/src/android/camera_capabilities.cpp\n@@ -262,6 +262,149 @@ std::vector<T> setMetadata(CameraMetadata *metadata, uint32_t tag,\n \treturn ret;\n }\n \n+\n+template<typename T>\n+bool metadataContains(camera_metadata_ro_entry_t &entry, T value);\n+\n+template<>\n+bool metadataContains<uint8_t>(camera_metadata_ro_entry_t &entry, uint8_t value)\n+{\n+\tfor (unsigned int i = 0; i < entry.count; i++)\n+\t\tif (entry.data.u8[i] == value)\n+\t\t\treturn true;\n+\n+\treturn false;\n+}\n+\n+bool validateManualSensorCapability(CameraMetadata *staticMetadata)\n+{\n+\tcamera_metadata_ro_entry_t entry;\n+\tbool found;\n+\n+\tfound = staticMetadata->getEntry(ANDROID_CONTROL_AE_AVAILABLE_MODES,\n+\t\t\t\t\t &entry);\n+\tif (!found || !metadataContains<uint8_t>(entry, ANDROID_CONTROL_AE_MODE_OFF)) {\n+\t\tLOG(HAL, Info)\n+\t\t\t<< \"Missing AE mode off: \"\n+\t\t\t<< (found ? \"not supported\" : \"not found\");\n+\t\treturn false;\n+\t}\n+\n+\tfound = staticMetadata->getEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE,\n+\t\t\t\t\t &entry);\n+\tif (!found || !(*entry.data.u8 == ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE)) {\n+\t\tLOG(HAL, Info) << \"Missing AE lock\";\n+\t\treturn false;\n+\t}\n+\n+\tfound = staticMetadata->getEntry(ANDROID_EDGE_AVAILABLE_EDGE_MODES,\n+\t\t\t\t\t &entry);\n+\tif (!found) {\n+\t\tLOG(HAL, Info) << \"Missing edge modes\";\n+\t\treturn false;\n+\t}\n+\n+\treturn true;\n+}\n+\n+bool validateManualPostProcessingCapability(CameraMetadata *staticMetadata)\n+{\n+\tcamera_metadata_ro_entry_t entry;\n+\tbool found;\n+\n+\tfound = staticMetadata->getEntry(ANDROID_CONTROL_AWB_AVAILABLE_MODES,\n+\t\t\t\t\t &entry);\n+\tif (!found || !metadataContains<uint8_t>(entry, ANDROID_CONTROL_AWB_MODE_OFF)) {\n+\t\tLOG(HAL, Info) << \"Missing AWB mode off\";\n+\t\treturn false;\n+\t}\n+\n+\tfound = staticMetadata->getEntry(ANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n+\t\t\t\t\t &entry);\n+\tif (!found || !(*entry.data.u8 == ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE)) {\n+\t\tLOG(HAL, Info) << \"Missing AWB lock\";\n+\t\treturn false;\n+\t}\n+\n+\treturn true;\n+}\n+\n+bool validateBurstCaptureCapability(CameraMetadata *staticMetadata)\n+{\n+\tcamera_metadata_ro_entry_t entry;\n+\tbool found;\n+\n+\tfound = staticMetadata->getEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE,\n+\t\t\t\t\t &entry);\n+\tif (!found || !(*entry.data.u8 == ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE)) {\n+\t\tLOG(HAL, Info) << \"Missing AE lock\";\n+\t\treturn false;\n+\t}\n+\n+\tfound = staticMetadata->getEntry(ANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n+\t\t\t\t\t &entry);\n+\tif (!found || !(*entry.data.u8 == ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE)) {\n+\t\tLOG(HAL, Info) << \"Missing AWB lock\";\n+\t\treturn false;\n+\t}\n+\n+\tfound = staticMetadata->getEntry(ANDROID_SYNC_MAX_LATENCY, &entry);\n+\tif (!found || *entry.data.i32 < 0 || 4 < *entry.data.i32) {\n+\t\tLOG(HAL, Info)\n+\t\t\t<< \"Max sync latency is \"\n+\t\t\t<< (found ? std::to_string(*entry.data.i32) : \"not present\");\n+\t\treturn false;\n+\t}\n+\n+\treturn true;\n+}\n+\n+std::set<camera_metadata_enum_android_request_available_capabilities>\n+computeCapabilities(CameraMetadata *staticMetadata,\n+\t\t    std::set<camera_metadata_enum_android_request_available_capabilities> &existingCaps)\n+{\n+\tstd::set<camera_metadata_enum_android_request_available_capabilities>\n+\tcapabilities = existingCaps;\n+\n+\tcapabilities.insert(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);\n+\n+\tif (validateManualSensorCapability(staticMetadata))\n+\t\tcapabilities.insert(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR);\n+\n+\tif (validateManualPostProcessingCapability(staticMetadata))\n+\t\tcapabilities.insert(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING);\n+\n+\tif (validateBurstCaptureCapability(staticMetadata))\n+\t\tcapabilities.insert(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE);\n+\n+\treturn capabilities;\n+}\n+\n+camera_metadata_enum_android_info_supported_hardware_level\n+computeHwLevel(CameraMetadata *staticMetadata,\n+\t       std::set<camera_metadata_enum_android_request_available_capabilities> capabilities)\n+{\n+\tcamera_metadata_ro_entry_t entry;\n+\tbool found;\n+\tcamera_metadata_enum_android_info_supported_hardware_level\n+\t\thwLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL;\n+\n+\tif (!capabilities.count(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR))\n+\t\thwLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;\n+\n+\tif (!capabilities.count(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING))\n+\t\thwLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;\n+\n+\tif (!capabilities.count(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE))\n+\t\thwLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;\n+\n+\tfound = staticMetadata->getEntry(ANDROID_SYNC_MAX_LATENCY, &entry);\n+\tif (!found || *entry.data.i32 != 0)\n+\t\thwLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;\n+\n+\treturn hwLevel;\n+}\n+\n } /* namespace */\n \n int CameraCapabilities::initialize(std::shared_ptr<libcamera::Camera> camera,\n@@ -655,17 +798,7 @@ int CameraCapabilities::initializeStaticMetadata()\n \t};\n \n \tstd::set<camera_metadata_enum_android_request_available_capabilities>\n-\tcapabilities = {\n-\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE,\n-\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR,\n-\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING,\n-\t\tANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE,\n-\t};\n-\n-\tstd::set<camera_metadata_enum_android_info_supported_hardware_level>\n-\thwLevels = {\n-\t\tANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL,\n-\t};\n+\tcapabilities = {};\n \n \t/* Color correction static metadata. */\n \t{\n@@ -692,19 +825,12 @@ int CameraCapabilities::initializeStaticMetadata()\n \tstaticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES,\n \t\t\t\t  aeAvailableAntiBandingModes);\n \n-\tstd::vector<uint8_t> aeModes = setMetadata<uint8_t, bool>(\n+\tsetMetadata<uint8_t, bool>(\n \t\tstaticMetadata_.get(),\n \t\tANDROID_CONTROL_AE_AVAILABLE_MODES,\n \t\tcontrolsInfo, &controls::AeEnable,\n \t\t{ ANDROID_CONTROL_AE_MODE_ON });\n \n-\tif (std::find(aeModes.begin(), aeModes.end(),\n-\t\t      ANDROID_CONTROL_AE_MODE_OFF) == aeModes.end()) {\n-\t\tLOG(HAL, Info) << \"AE cannot be turned off\";\n-\t\thwLevels.erase(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL);\n-\t\tcapabilities.erase(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR);\n-\t}\n-\n \tint64_t minFrameDurationNsec = -1;\n \tint64_t maxFrameDurationNsec = -1;\n \tconst auto frameDurationsInfo = controlsInfo.find(&controls::FrameDurationLimits);\n@@ -791,17 +917,11 @@ int CameraCapabilities::initializeStaticMetadata()\n \tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES,\n \t\t\t\t  availableStabilizationModes);\n \n-\tstd::vector<uint8_t> awbModes = setMetadata<uint8_t, int32_t>(\n+\tsetMetadata<uint8_t, int32_t>(\n \t\tstaticMetadata_.get(),\n \t\tANDROID_CONTROL_AWB_AVAILABLE_MODES,\n \t\tcontrolsInfo, &controls::AwbMode,\n \t\t{ ANDROID_CONTROL_AWB_MODE_AUTO });\n-\tif (std::find(awbModes.begin(), awbModes.end(),\n-\t\t      ANDROID_CONTROL_AWB_MODE_OFF) == awbModes.end()) {\n-\t\tLOG(HAL, Info) << \"AWB cannot be turned off\";\n-\t\thwLevels.erase(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL);\n-\t\tcapabilities.erase(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING);\n-\t}\n \n \tstd::vector<int32_t> availableMaxRegions = {\n \t\t0, 0, 0,\n@@ -817,29 +937,19 @@ int CameraCapabilities::initializeStaticMetadata()\n \tstaticMetadata_->addEntry(ANDROID_CONTROL_SCENE_MODE_OVERRIDES,\n \t\t\t\t  sceneModesOverride);\n \n-\tuint8_t aeLockAvailable = setMetadata<uint8_t, bool>(\n+\tsetMetadata<uint8_t, bool>(\n \t\tstaticMetadata_.get(),\n \t\tANDROID_CONTROL_AE_LOCK_AVAILABLE,\n \t\tcontrolsInfo, &controls::AeLock,\n \t\tControlRange::Max,\n \t\tANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE);\n-\tif (aeLockAvailable != ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE) {\n-\t\tLOG(HAL, Info) << \"AE lock is unavailable\";\n-\t\tcapabilities.erase(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE);\n-\t\tcapabilities.erase(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR);\n-\t}\n \n-\tuint8_t awbLockAvailable = setMetadata<uint8_t, bool>(\n+\tsetMetadata<uint8_t, bool>(\n \t\tstaticMetadata_.get(),\n \t\tANDROID_CONTROL_AWB_LOCK_AVAILABLE,\n \t\tcontrolsInfo, &controls::AwbLock,\n \t\tControlRange::Max,\n \t\tANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE);\n-\tif (awbLockAvailable != ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE) {\n-\t\tLOG(HAL, Info) << \"AWB lock is unavailable\";\n-\t\tcapabilities.erase(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE);\n-\t\tcapabilities.erase(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING);\n-\t}\n \n \tchar availableControlModes = ANDROID_CONTROL_MODE_AUTO;\n \tstaticMetadata_->addEntry(ANDROID_CONTROL_AVAILABLE_MODES,\n@@ -859,10 +969,6 @@ int CameraCapabilities::initializeStaticMetadata()\n \t\tavailableCharacteristicsKeys_.insert(ANDROID_EDGE_AVAILABLE_EDGE_MODES);\n \t\tavailableRequestKeys_.insert(ANDROID_EDGE_MODE);\n \t\tavailableResultKeys_.insert(ANDROID_EDGE_MODE);\n-\t} else {\n-\t\tLOG(HAL, Info) << \"Edge mode unavailable\";\n-\t\thwLevels.erase(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL);\n-\t\tcapabilities.erase(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR);\n \t}\n \n \t/* JPEG static metadata. */\n@@ -1046,17 +1152,11 @@ int CameraCapabilities::initializeStaticMetadata()\n \t}\n \n \t/* Sync static metadata. */\n-\tint32_t maxLatency = setMetadata<int32_t, int32_t>(\n+\tsetMetadata<int32_t, int32_t>(\n \t\tstaticMetadata_.get(), ANDROID_SYNC_MAX_LATENCY,\n \t\tcontrolsInfo, &controls::draft::MaxLatency,\n \t\tControlRange::Def,\n \t\tANDROID_SYNC_MAX_LATENCY_UNKNOWN);\n-\tLOG(HAL, Info) << \"Max sync latency is \" << maxLatency;\n-\t/* CTS allows a sync latency of up to 4 for burst capture capability */\n-\tif (maxLatency < 0 || 4 < maxLatency)\n-\t\tcapabilities.erase(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE);\n-\tif (maxLatency != 0)\n-\t\thwLevels.erase(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL);\n \n \t/* Flash static metadata. */\n \tchar flashAvailable = ANDROID_FLASH_INFO_AVAILABLE_FALSE;\n@@ -1220,19 +1320,14 @@ int CameraCapabilities::initializeStaticMetadata()\n \t\t\t\t  numOutStreams);\n \n \t/* Check capabilities */\n-\tstd::vector<uint8_t> availableCapabilities(capabilities.begin(),\n-\t\t\t\t\t\t   capabilities.end());\n-\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CAPABILITIES,\n-\t\t\t\t  availableCapabilities);\n-\n-\tuint8_t hwLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;\n-\tif (capabilities.count(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR) &&\n-\t    capabilities.count(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MANUAL_POST_PROCESSING) &&\n-\t    capabilities.count(ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE) &&\n-\t    hwLevels.count(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL))\n-\t\thwLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL;\n-\tstaticMetadata_->addEntry(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL,\n-\t\t\t\t  hwLevel);\n+\tcapabilities = computeCapabilities(staticMetadata_.get(), capabilities);\n+\tstd::vector<camera_metadata_enum_android_request_available_capabilities>\n+\t\tcapsVec = std::vector<camera_metadata_enum_android_request_available_capabilities>(capabilities.begin(), capabilities.end());\n+\tstaticMetadata_->addEntry(ANDROID_REQUEST_AVAILABLE_CAPABILITIES, capsVec);\n+\n+\tcamera_metadata_enum_android_info_supported_hardware_level hwLevel =\n+\t\tcomputeHwLevel(staticMetadata_.get(), capabilities);\n+\tstaticMetadata_->addEntry(ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, hwLevel);\n \n \tLOG(HAL, Info)\n \t\t<< \"Hardware level: \"\n","prefixes":["libcamera-devel","RFC"]}