From patchwork Tue Dec 21 04:36:08 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul Elder X-Patchwork-Id: 15184 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 BC0D0C3259 for ; Tue, 21 Dec 2021 04:36:29 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 326BF60900; Tue, 21 Dec 2021 05:36:29 +0100 (CET) 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="WnU0IEU8"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3A023608F8 for ; Tue, 21 Dec 2021 05:36:26 +0100 (CET) Received: from pyrite.mediacom.info (unknown [IPv6:2604:2d80:ad90:fb00:96fd:8874:873:6c16]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 55BD2881; Tue, 21 Dec 2021 05:36:25 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1640061386; bh=MyRNP/dDBWmJxj5zE8GNAUEn8v6pO9tLjUCL9N+TAy8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WnU0IEU8eGaJaedGE9Dx+soRM+N9swY/5Mq4bdQ28lzX3Rzm5UueAEIrRLtgp2wQV lqex/PTy2/qj9Q6M6LKZwzMxhM/RRwwlJORJwDS45NSQDvIiH+UIDgr51OX8TBhBAz iIFUlHQQmsLLvkSWGKJPEp1wFg+g/Q50Z5rmuEmc= From: Paul Elder To: libcamera-devel@lists.libcamera.org Date: Mon, 20 Dec 2021 22:36:08 -0600 Message-Id: <20211221043610.2512334-7-paul.elder@ideasonboard.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20211221043610.2512334-1-paul.elder@ideasonboard.com> References: <20211221043610.2512334-1-paul.elder@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v3 6/8] 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) - preview template: set exposure time to the minimum in the exposure time range - 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 --- Changes in v3: - rename AeMode to AutoMode as we'll also use it for awb later - set the exposure time in the preview template - a bunch of other big changes (mentioned by Jacopo, and discussed a bit) were not done, as more discussion is needed New in v2 --- src/android/camera_capabilities.cpp | 71 +++++++++++++++++++--- src/android/camera_device.cpp | 93 +++++++++++++++++++++++++++-- src/android/camera_device.h | 13 ++++ src/android/camera_request.h | 9 +++ 4 files changed, 174 insertions(+), 12 deletions(-) diff --git a/src/android/camera_capabilities.cpp b/src/android/camera_capabilities.cpp index a2e42a5c..318ab666 100644 --- a/src/android/camera_capabilities.cpp +++ b/src/android/camera_capabilities.cpp @@ -922,12 +922,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); + std::vector aeCompensationRange = { 0, 0, }; @@ -988,10 +1038,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); @@ -1468,6 +1514,12 @@ std::unique_ptr CameraCapabilities::requestTemplateManual() cons manualTemplate->appendEntry(ANDROID_CONTROL_MODE, mode); } + if (staticMetadata_->entryContains(ANDROID_CONTROL_AE_AVAILABLE_MODES, + ANDROID_CONTROL_AE_MODE_OFF)) { + uint8_t aeMode = ANDROID_CONTROL_AE_MODE_OFF; + manualTemplate->appendEntry(ANDROID_CONTROL_AE_MODE, aeMode); + } + return manualTemplate; } @@ -1542,6 +1594,11 @@ std::unique_ptr CameraCapabilities::requestTemplatePreview() con uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF; requestTemplate->addEntry(ANDROID_CONTROL_AWB_LOCK, awbLock); + if (availableRequestKeys_.count(ANDROID_SENSOR_EXPOSURE_TIME)) { + staticMetadata_->getEntry(ANDROID_SENSOR_INFO_EXPOSURE_TIME_RANGE, &entry); + requestTemplate->addEntry(ANDROID_SENSOR_EXPOSURE_TIME, entry.data.i64[0]); + } + uint8_t flashMode = ANDROID_FLASH_MODE_OFF; requestTemplate->addEntry(ANDROID_FLASH_MODE, flashMode); diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp index 83825736..3ade44c4 100644 --- a/src/android/camera_device.cpp +++ b/src/android/camera_device.cpp @@ -246,7 +246,9 @@ bool validateCropRotate(const camera3_stream_configuration_t &streamList) 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); @@ -812,6 +814,59 @@ 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; + + Camera3RequestDescriptor::AutoMode aeMode; + if (aeLocked_ && aeOn_) + aeMode = Camera3RequestDescriptor::AutoMode::Lock; + else if (aeLocked_ && !aeOn_) + aeMode = Camera3RequestDescriptor::AutoMode::Manual; + else if (!aeLocked_ && aeOn_) + aeMode = Camera3RequestDescriptor::AutoMode::Auto; + else /* !aeLocked_ && !aeOn_ */ + aeMode = Camera3RequestDescriptor::AutoMode::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 == Camera3RequestDescriptor::AutoMode::Auto ? + controls::ExposureTimeModeAuto : + controls::ExposureTimeModeDisabled); + } + + const auto &gInfo = camera_->controls().find(&controls::AnalogueGainMode); + if (gInfo != camera_->controls().end()) { + controls.set(controls::AnalogueGainMode, + aeMode == Camera3RequestDescriptor::AutoMode::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; + } + } + + /* Trigger libcamera's locked -> manual state change */ + if (aeMode == Camera3RequestDescriptor::AutoMode::Manual) { + const auto &info = camera_->controls().find(&controls::ExposureTime); + if (info != camera_->controls().end()) + controls.set(controls::ExposureTime, lastExposureTime_); + } + return 0; } @@ -1336,11 +1391,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_ == Camera3RequestDescriptor::AutoMode::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_ != Camera3RequestDescriptor::AutoMode::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)) /* @@ -1357,6 +1417,29 @@ 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: + LOG(HAL, Error) << "Invalid AeState, setting converged"; + } + } + if (descriptor.aeMode_ == Camera3RequestDescriptor::AutoMode::Lock) + value = ANDROID_CONTROL_AE_STATE_LOCKED; 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 64050416..a65f1670 100644 --- a/src/android/camera_device.h +++ b/src/android/camera_device.h @@ -126,5 +126,18 @@ private: int facing_; int orientation_; + /* + * Normally resubmission of controls would be handled on libcamera's + * side, but these controls are not one-to-one between libcamera and + * android, so we need to save them here + */ + + /* Track the last-set android AE controls */ + bool aeOn_; + bool aeLocked_; + int32_t lastExposureTime_; + float lastAnalogueGain_; + float lastDigitalGain_; + CameraMetadata lastSettings_; }; diff --git a/src/android/camera_request.h b/src/android/camera_request.h index 37b6ae32..b2809179 100644 --- a/src/android/camera_request.h +++ b/src/android/camera_request.h @@ -28,6 +28,12 @@ class CameraStream; class Camera3RequestDescriptor { public: + enum class AutoMode { + Auto, + Lock, + Manual, + }; + enum class Status { Success, Error, @@ -78,6 +84,9 @@ public: bool complete_ = false; Status status_ = Status::Success; + /* The libcamera internal AE state for this request */ + AutoMode aeMode_ = AutoMode::Auto; + private: LIBCAMERA_DISABLE_COPY(Camera3RequestDescriptor) };