From patchwork Fri Oct 1 10:33:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 14021 X-Patchwork-Delegate: paul.elder@ideasonboard.com Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 79B7EBDC71 for ; Fri, 1 Oct 2021 10:33:49 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 41197691B6; Fri, 1 Oct 2021 12:33:49 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="G99FhBgo"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3E153691AA for ; Fri, 1 Oct 2021 12:33:48 +0200 (CEST) Received: from pyrite.rasen.tech (unknown [IPv6:2400:4051:61:600:2c71:1b79:d06d:5032]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id CC763A16; Fri, 1 Oct 2021 12:33:46 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1633084428; bh=2JdAS4NO+dDKWBHjAjtpumf0GTZhtUlaaonJgmNDkmI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=G99FhBgoJWg85Q4gALp9rJjCzoYGXdDBLI50eFtGZInl7lEUz9KtG66CYVXrk4ESk j1OyDTsUHalCK2/WzMDQP7U+NJvQ0wwja7+P5aaQ0tcMTVZMc+0HrIQ1T1kgOpK9Z4 t+x+Yd3Xb2Y4AYbXgzLCgAvWN2shg/je8kckW37w= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Fri, 1 Oct 2021 19:33:24 +0900 Message-Id: <20211001103325.1077590-7-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20211001103325.1077590-1-paul.elder@ideasonboard.com> References: <20211001103325.1077590-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 6/7] android: Plumb all AE-related controls X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" With the AE-related controls reorganized in libcamera, with separate value and lever controls for exposure and gain, plumb these through the HAL layer (in order of appearence in the patch): - static metadata: available AE modes, AE lock available - manual template: add AE off (the other templates already have AE on) - request metadata: HAL -> libcamera controls conversion - result metadata: libcamera -> HAL controls conversion - result metadata: AE state We add class variables to CameraDevice to save the last set android AE controls, as that is how android controls function (no need to resubmit controls if they are unchanged). We also save libcamera's AE state in the request descriptor, as otherwise there is insufficient information from libcamera's result metadata alone to tell if the state is locked or manual (as they are an internal state in libcamera). Bug: https://bugs.libcamera.org/show_bug.cgi?id=42 Bug: https://bugs.libcamera.org/show_bug.cgi?id=43 Bug: https://bugs.libcamera.org/show_bug.cgi?id=47 Signed-off-by: Paul Elder --- New in v2 --- src/android/camera_capabilities.cpp | 63 ++++++++++++++++--- src/android/camera_device.cpp | 98 +++++++++++++++++++++++++++-- src/android/camera_device.h | 16 +++++ 3 files changed, 165 insertions(+), 12 deletions(-) diff --git a/src/android/camera_capabilities.cpp b/src/android/camera_capabilities.cpp index f7a6cda9..3fed3f83 100644 --- a/src/android/camera_capabilities.cpp +++ b/src/android/camera_capabilities.cpp @@ -830,12 +830,62 @@ int CameraCapabilities::initializeStaticMetadata() staticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES, aeAvailableAntiBandingModes); - std::vector aeAvailableModes = { - ANDROID_CONTROL_AE_MODE_ON, - }; + std::vector aeAvailableModes; + /* This will cause problems if one supports only on and the other only off */ + bool aeAddedOn = false; + bool aeAddedOff = false; + + const auto &analogGainModeInfo = controlsInfo.find(&controls::AnalogueGainMode); + if (analogGainModeInfo != controlsInfo.end()) { + for (const auto &value : analogGainModeInfo->second.values()) { + switch (value.get()) { + case controls::AnalogueGainModeAuto: + if (!aeAddedOn) + aeAvailableModes.push_back(ANDROID_CONTROL_AE_MODE_ON); + aeAddedOn = true; + break; + case controls::AnalogueGainModeDisabled: + if (!aeAddedOff) + aeAvailableModes.push_back(ANDROID_CONTROL_AE_MODE_OFF); + aeAddedOff = true; + break; + default: + break; + } + } + } + + const auto &exposureTimeModeInfo = controlsInfo.find(&controls::ExposureTimeMode); + if (exposureTimeModeInfo != controlsInfo.end()) { + for (const auto &value : exposureTimeModeInfo->second.values()) { + switch (value.get()) { + case controls::ExposureTimeModeAuto: + if (!aeAddedOn) + aeAvailableModes.push_back(ANDROID_CONTROL_AE_MODE_ON); + aeAddedOn = true; + break; + case controls::ExposureTimeModeDisabled: + if (!aeAddedOff) + aeAvailableModes.push_back(ANDROID_CONTROL_AE_MODE_OFF); + aeAddedOff = true; + break; + default: + break; + } + } + } + + if (aeAvailableModes.empty()) + aeAvailableModes.push_back(ANDROID_CONTROL_AE_MODE_ON); staticMetadata_->addEntry(ANDROID_CONTROL_AE_AVAILABLE_MODES, aeAvailableModes); + /* In libcamera, turning off AE is equivalient to locking. */ + uint8_t aeLockAvailable = aeAddedOff ? ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE + : ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE; + staticMetadata_->addEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE, + aeLockAvailable); + int64_t minFrameDurationNsec = -1; int64_t maxFrameDurationNsec = -1; const auto frameDurationsInfo = controlsInfo.find(&controls::FrameDurationLimits); @@ -946,10 +996,6 @@ int CameraCapabilities::initializeStaticMetadata() staticMetadata_->addEntry(ANDROID_CONTROL_SCENE_MODE_OVERRIDES, sceneModesOverride); - uint8_t aeLockAvailable = ANDROID_CONTROL_AE_LOCK_AVAILABLE_FALSE; - staticMetadata_->addEntry(ANDROID_CONTROL_AE_LOCK_AVAILABLE, - aeLockAvailable); - uint8_t awbLockAvailable = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_FALSE; staticMetadata_->addEntry(ANDROID_CONTROL_AWB_LOCK_AVAILABLE, awbLockAvailable); @@ -1358,6 +1404,9 @@ std::unique_ptr CameraCapabilities::requestTemplateManual() cons if (!manualTemplate) return nullptr; + uint8_t aeMode = ANDROID_CONTROL_AE_MODE_OFF; + manualTemplate->addEntry(ANDROID_CONTROL_AE_MODE, aeMode); + return manualTemplate; } diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp index ef4fbab8..d5027ec5 100644 --- a/src/android/camera_device.cpp +++ b/src/android/camera_device.cpp @@ -263,7 +263,9 @@ CameraDevice::Camera3RequestDescriptor::Camera3RequestDescriptor( CameraDevice::CameraDevice(unsigned int id, std::shared_ptr camera) : id_(id), state_(State::Stopped), camera_(std::move(camera)), - facing_(CAMERA_FACING_FRONT), orientation_(0) + facing_(CAMERA_FACING_FRONT), orientation_(0), + aeOn_(true), aeLocked_(false), lastExposureTime_(0), + lastAnalogueGain_(1.0f), lastDigitalGain_(1.0f) { camera_->requestCompleted.connect(this, &CameraDevice::requestComplete); @@ -857,6 +859,62 @@ int CameraDevice::processControls(Camera3RequestDescriptor *descriptor) controls.set(controls::draft::TestPatternMode, testPatternMode); } + /* + * \todo Can we trust that we won't receive values that we didn't + * report supporting? + */ + if (settings.getEntry(ANDROID_CONTROL_AE_LOCK, &entry)) + aeLocked_ = *entry.data.u8 != ANDROID_CONTROL_AE_LOCK_OFF; + + if (settings.getEntry(ANDROID_CONTROL_AE_MODE, &entry)) + aeOn_ = *entry.data.u8 != ANDROID_CONTROL_AE_MODE_OFF; + + AeMode aeMode; + if (aeLocked_ && aeOn_) + aeMode = AeMode::Lock; + else if (aeLocked_ && !aeOn_) + aeMode = AeMode::Manual; + else if (!aeLocked_ && aeOn_) + aeMode = AeMode::Auto; + else /* !aeLocked_ && !aeOn_ */ + aeMode = AeMode::Manual; + + /* Save this so that we can recover it in the result */ + descriptor->aeMode_ = aeMode; + + const auto &eInfo = camera_->controls().find(&controls::ExposureTimeMode); + if (eInfo != camera_->controls().end()) { + controls.set(controls::ExposureTimeMode, + aeMode == AeMode::Auto ? + controls::ExposureTimeModeAuto : + controls::ExposureTimeModeDisabled); + } + + const auto &gInfo = camera_->controls().find(&controls::AnalogueGainMode); + if (gInfo != camera_->controls().end()) { + controls.set(controls::AnalogueGainMode, + aeMode == AeMode::Auto ? + controls::AnalogueGainModeAuto : + controls::AnalogueGainModeDisabled); + } + + if (settings.getEntry(ANDROID_SENSOR_EXPOSURE_TIME, &entry)) { + const auto &info = camera_->controls().find(&controls::ExposureTime); + if (info != camera_->controls().end()) { + lastExposureTime_ = (*entry.data.i64) / 1000; + /* Don't disable libcamera's internal AeMode::Lock */ + if (aeMode != AeMode::Lock) + controls.set(controls::ExposureTime, lastExposureTime_); + } + } + + /* Trigger libcamera's locked -> manual state change */ + if (aeMode == AeMode::Manual && !settings.hasEntry(ANDROID_SENSOR_EXPOSURE_TIME)) { + const auto &info = camera_->controls().find(&controls::ExposureTime); + if (info != camera_->controls().end()) + controls.set(controls::ExposureTime, lastExposureTime_); + } + return 0; } @@ -1345,11 +1403,16 @@ CameraDevice::getResultMetadata(const Camera3RequestDescriptor &descriptor) cons resultMetadata->addEntry(ANDROID_CONTROL_AE_EXPOSURE_COMPENSATION, value32); - value = ANDROID_CONTROL_AE_LOCK_OFF; - resultMetadata->addEntry(ANDROID_CONTROL_AE_LOCK, value); + uint8_t aeLock = (descriptor.aeMode_ == AeMode::Lock) + ? ANDROID_CONTROL_AE_LOCK_ON + : ANDROID_CONTROL_AE_LOCK_OFF; + resultMetadata->addEntry(ANDROID_CONTROL_AE_LOCK, aeLock); - value = ANDROID_CONTROL_AE_MODE_ON; - resultMetadata->addEntry(ANDROID_CONTROL_AE_MODE, value); + /* Locked means auto + locked in android */ + uint8_t aeMode = (descriptor.aeMode_ != AeMode::Manual) + ? ANDROID_CONTROL_AE_MODE_ON + : ANDROID_CONTROL_AE_MODE_OFF; + resultMetadata->addEntry(ANDROID_CONTROL_AE_MODE, aeMode); if (settings.getEntry(ANDROID_CONTROL_AE_TARGET_FPS_RANGE, &entry)) /* @@ -1366,6 +1429,31 @@ CameraDevice::getResultMetadata(const Camera3RequestDescriptor &descriptor) cons resultMetadata->addEntry(ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER, value); value = ANDROID_CONTROL_AE_STATE_CONVERGED; + if (metadata.contains(controls::AeState)) { + switch (metadata.get(controls::AeState)) { + case controls::AeStateInactive: + value = ANDROID_CONTROL_AE_STATE_INACTIVE; + break; + case controls::AeStateSearching: + value = ANDROID_CONTROL_AE_STATE_SEARCHING; + break; + case controls::AeStateConverged: + value = ANDROID_CONTROL_AE_STATE_CONVERGED; + break; + case controls::AeStateFlashRequired: + value = ANDROID_CONTROL_AE_STATE_FLASH_REQUIRED; + break; + case controls::AeStatePrecapture: + value = ANDROID_CONTROL_AE_STATE_PRECAPTURE; + break; + default: + if (descriptor.aeMode_ == AeMode::Lock) { + value = ANDROID_CONTROL_AE_STATE_LOCKED; + break; + } + LOG(HAL, Error) << "Invalid AeState, setting converged"; + } + } resultMetadata->addEntry(ANDROID_CONTROL_AE_STATE, value); value = ANDROID_CONTROL_AF_MODE_OFF; diff --git a/src/android/camera_device.h b/src/android/camera_device.h index b7d774fe..f693cdbc 100644 --- a/src/android/camera_device.h +++ b/src/android/camera_device.h @@ -73,6 +73,12 @@ private: CameraDevice(unsigned int id, std::shared_ptr camera); + enum class AeMode { + Auto, + Lock, + Manual, + }; + struct Camera3RequestDescriptor { enum class Status { Pending, @@ -96,6 +102,9 @@ private: camera3_capture_result_t captureResult_ = {}; Status status_ = Status::Pending; + + /* The libcamera internal AE state for this request */ + AeMode aeMode_ = AeMode::Auto; }; enum class State { @@ -146,6 +155,13 @@ private: int facing_; int orientation_; + /* Track the last-set android AE controls */ + bool aeOn_; + bool aeLocked_; + int32_t lastExposureTime_; + float lastAnalogueGain_; + float lastDigitalGain_; + CameraMetadata lastSettings_; };