blob: 965575632238a8b3be64d8e27177499563b352b7 [file] [log] [blame]
/*
* Copyright (C) 2017-2019 Intel Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "ControlUnit"
#include "LogHelper.h"
#include "PerformanceTraces.h"
#include "ControlUnit.h"
#include "IPU3CameraHw.h"
#include "CaptureUnit.h"
#include "ImguUnit.h"
#include "CameraStream.h"
#include "IPU3CapturedStatistics.h"
#include "IPU3CameraCapInfo.h"
#include "CameraMetadataHelper.h"
#include "PlatformData.h"
#include "ProcUnitSettings.h"
#include "LensHw.h"
#include "SettingsProcessor.h"
#include "Metadata.h"
#include "AAARunner.h"
namespace cros {
namespace intel {
ControlUnit::ControlUnit(ImguUnit *thePU,
CaptureUnit *theCU,
int cameraId,
IStreamConfigProvider &aStreamCfgProv,
FaceEngine* faceEngine) :
mRequestStatePool("CtrlReqState"),
mCaptureUnitSettingsPool("CapUSettings"),
mProcUnitSettingsPool("ProcUSettings"),
mLatestStatistics(nullptr),
mLatestRequestId(-1),
mImguUnit(thePU),
mCaptureUnit(theCU),
m3aWrapper(nullptr),
mCameraId(cameraId),
mErrCb(nullptr),
mCameraThread("CtrlUThread"),
mBaseIso(100),
mStreamCfgProv(aStreamCfgProv),
mSettingsProcessor(nullptr),
mMetadata(nullptr),
m3ARunner(nullptr),
mLensController(nullptr),
mFaceEngine(faceEngine)
{
}
status_t
ControlUnit::init()
{
HAL_TRACE_CALL(CAMERA_DEBUG_LOG_LEVEL1, LOG_TAG);
if (!mCameraThread.Start()) {
LOGE("Camera thread failed to start");
return UNKNOWN_ERROR;
}
const IPU3CameraCapInfo *cap = getIPU3CameraCapInfo(mCameraId);
CheckError(!cap, UNKNOWN_ERROR, "Not enough information for getting NVM data");
CheckError(cap->sensorType() != SENSOR_TYPE_RAW, UNKNOWN_ERROR, "SoC camera 3A control missing");
m3aWrapper = new Intel3aPlus(mCameraId);
m3aWrapper->enableAiqdDataSave(true);
status_t status = m3aWrapper->initAIQ(MAX_STATISTICS_WIDTH,
MAX_STATISTICS_HEIGHT,
cap->getNvmData(),
cap->getSensorName());
CheckError(status != NO_ERROR, UNKNOWN_ERROR, "Error initializing 3A control");
mSettingsProcessor = new SettingsProcessor(mCameraId, m3aWrapper, mStreamCfgProv);
mSettingsProcessor->init();
mMetadata = new Metadata(mCameraId, m3aWrapper);
status = mMetadata->init();
mCaptureUnit->setSettingsProcessor(mSettingsProcessor);
/*
* init the pools of Request State structs and CaptureUnit settings
* and Processing Unit Settings
*/
mRequestStatePool.init(MAX_REQUEST_IN_PROCESS_NUM, RequestCtrlState::reset);
mCaptureUnitSettingsPool.init(SETTINGS_POOL_SIZE + 2);
mProcUnitSettingsPool.init(SETTINGS_POOL_SIZE, ProcUnitSettings::reset);
/*
* Retrieve the Lens Controller interface from Capture Unit
*/
LensHw *lensController = mCaptureUnit->getLensControlInterface();
mSettingsHistory.clear();
/* Set ISO map support */
bool supportIsoMap = cap->getSupportIsoMap();
m3aWrapper->setSupportIsoMap(supportIsoMap);
m3ARunner = new AAARunner(mCameraId, m3aWrapper, mSettingsProcessor, lensController);
/* Set digi gain support */
bool supportDigiGain = cap->digiGainOnSensor();
status = m3ARunner->init(supportDigiGain);
status = allocateLscResults();
if (CC_UNLIKELY(status != OK)) {
LOGE("Failed to allocate LSC results");
return NO_MEMORY;
}
return status;
}
/**
* allocateLscResults
*
* Allocates the size of the LSC tables used as part of the AIQ results
* that the 3A algorithms produce.
* This allocation is done dynamically since it depends on the sensor.
*
* Since cmc is read here, base_iso is stored in this function also.
*
* The memory will be freed by the AiqResult destructor.
*
*/
status_t ControlUnit::allocateLscResults()
{
HAL_TRACE_CALL(CAMERA_DEBUG_LOG_LEVEL1, LOG_TAG);
status_t status = OK;
std::shared_ptr<CaptureUnitSettings> capSettings = nullptr;
ia_binary_data cpfData;
ia_cmc_t *cmcData = nullptr;
PlatformData::getCpfAndCmc(cpfData, &cmcData, nullptr, mCameraId);
if (!cmcData) {
LOGE("No CMC data available for sensor. fix the CPF file!");
return UNKNOWN_ERROR;
}
if (cmcData && cmcData->cmc_sensitivity)
mBaseIso = cmcData->cmc_sensitivity->base_iso;
else
LOGW("Cannot get base iso from cmc");
if (!cmcData || !cmcData->cmc_parsed_lens_shading.cmc_lens_shading) {
LOGW("Lens shading grid not set in cmc");
return BAD_VALUE;
}
int tableH = cmcData->cmc_parsed_lens_shading.cmc_lens_shading->grid_height;
int tableW = cmcData->cmc_parsed_lens_shading.cmc_lens_shading->grid_width;
int tableSize = tableW * tableH;
if (tableSize == 0) {
LOGE("Invalid LSC table tize: fix the CPF file!");
return BAD_VALUE;
}
int poolSize = mCaptureUnitSettingsPool.availableItems();
for (int i = 0; i < poolSize; i++) {
mCaptureUnitSettingsPool.acquireItem(capSettings);
status = capSettings->aiqResults.allocateLsc(tableSize);
if (CC_UNLIKELY(status != OK)) {
break; // error reported outside
}
capSettings->aiqResults.init();
m3ARunner->initLsc(capSettings->aiqResults, tableSize);
}
if (status == OK)
status = m3ARunner->allocateLscTable(tableSize);
return status;
}
/**
* reset
*
* This method is called by the SharedPoolItem when the item is recycled
* At this stage we can cleanup before recycling the struct.
* In this case we reset the TracingSP of the capture unit settings and buffers
* to remove this reference. Other references may be still alive.
*/
void RequestCtrlState::reset(RequestCtrlState* me)
{
if (CC_LIKELY(me != nullptr)) {
me->captureSettings.reset();
me->processingSettings.reset();
me->captureBufs.rawBuffer.reset();
me->captureBufs.rawNonScaledBuffer.reset();
me->captureBufs.lastRawNonScaledBuffer.reset();
DELETE_ARRAY_AND_NULLIFY(me->rGammaLut);
DELETE_ARRAY_AND_NULLIFY(me->gGammaLut);
DELETE_ARRAY_AND_NULLIFY(me->bGammaLut);
} else {
LOGE("Trying to reset a null CtrlState structure !! - BUG ");
}
}
void RequestCtrlState::init(Camera3Request *req)
{
request = req;
aiqInputParams.init();
if (CC_LIKELY(captureSettings)) {
captureSettings->aiqResults.init();
captureSettings->aiqResults.requestId = req->getId();
captureSettings->afRegion.init(0);
captureSettings->aeRegion.init(0);
captureSettings->makernote.data = nullptr;
captureSettings->makernote.size = 0;
} else {
LOGE(" Failed to init Ctrl State struct: no capture settings!! - BUG");
return;
}
if (CC_LIKELY(processingSettings.get() != nullptr)) {
processingSettings->captureSettings = captureSettings;
processingSettings->request = req;
} else {
LOGE(" Failed to init Ctrl State: no processing settings!! - BUG");
return;
}
afState = ALGORITHM_NOT_CONFIG;
aeState = ALGORITHM_NOT_CONFIG;
awbState = ALGORITHM_NOT_CONFIG;
ctrlUnitResult = request->getPartialResultBuffer(CONTROL_UNIT_PARTIAL_RESULT);
statsArrived = false;
framesArrived = 0;
shutterDone = false;
blackLevelOff = false;
intent = ANDROID_CONTROL_CAPTURE_INTENT_PREVIEW;
aaaControls.ae.aeMode = ANDROID_CONTROL_AE_MODE_ON;
aaaControls.af.afMode = ANDROID_CONTROL_AF_MODE_AUTO;
aaaControls.af.afTrigger = ANDROID_CONTROL_AF_TRIGGER_IDLE;
aaaControls.awb.awbMode = ANDROID_CONTROL_AWB_MODE_AUTO;
aaaControls.controlMode = ANDROID_CONTROL_MODE_AUTO;
tonemapContrastCurve = false;
rGammaLut = nullptr;
gGammaLut = nullptr;
bGammaLut = nullptr;
rGammaLutSize = 0;
gGammaLutSize = 0;
bGammaLutSize = 0;
if (CC_UNLIKELY(ctrlUnitResult == nullptr)) {
LOGE("no partial result buffer - BUG");
return;
}
/**
* Apparently we need to have this tags in the results
*/
const android::CameraMetadata* settings = request->getSettings();
if (CC_UNLIKELY(settings == nullptr)) {
LOGE("no settings in request - BUG");
return;
}
camera_metadata_ro_entry entry;
entry = settings->find(ANDROID_REQUEST_ID);
if (entry.count == 1) {
ctrlUnitResult->update(ANDROID_REQUEST_ID, entry.data.i32,
entry.count);
}
int64_t id = captureSettings->aiqResults.requestId;
ctrlUnitResult->update(ANDROID_SYNC_FRAME_NUMBER,
&id, 1);
entry = settings->find(ANDROID_CONTROL_CAPTURE_INTENT);
if (entry.count == 1) {
intent = entry.data.u8[0];
}
ctrlUnitResult->update(ANDROID_CONTROL_CAPTURE_INTENT, entry.data.u8,
entry.count);
entry = settings->find(ANDROID_CONTROL_MODE);
if (entry.count == 1) {
aaaControls.controlMode = entry.data.u8[0];
ctrlUnitResult->update(ANDROID_CONTROL_MODE, entry.data.u8, entry.count);
}
entry = settings->find(ANDROID_CONTROL_AE_MODE);
if (entry.count == 1) {
aaaControls.ae.aeMode = entry.data.u8[0];
ctrlUnitResult->update(ANDROID_CONTROL_AE_MODE, entry.data.u8, entry.count);
}
}
ControlUnit::~ControlUnit()
{
HAL_TRACE_CALL(CAMERA_DEBUG_LOG_LEVEL1, LOG_TAG);
mLatestStatistics = nullptr;
mSettingsHistory.clear();
mCameraThread.Stop();
if (mSettingsProcessor) {
delete mSettingsProcessor;
mSettingsProcessor = nullptr;
}
if (m3aWrapper) {
m3aWrapper->deinit();
delete m3aWrapper;
m3aWrapper = nullptr;
}
delete mMetadata;
mMetadata = nullptr;
delete m3ARunner;
m3ARunner = nullptr;
}
void ControlUnit::registerErrorCallback(IErrorCallback *errCb)
{
LOG1("@%s, errCb:%p", __FUNCTION__, errCb);
mErrCb = errCb;
}
status_t
ControlUnit::configStreamsDone(bool configChanged)
{
LOG1("@%s: config changed: %d", __FUNCTION__, configChanged);
if (configChanged) {
mLatestRequestId = -1;
mPendingRequests.clear();
mWaitingForCapture.clear();
mSettingsHistory.clear();
}
return NO_ERROR;
}
/**
* acquireRequestStateStruct
*
* acquire a free request control state structure.
* Since this structure contains also a capture settings item that are also
* stored in a pool we need to acquire one of those as well.
*
*/
status_t
ControlUnit::acquireRequestStateStruct(std::shared_ptr<RequestCtrlState>& state)
{
status_t status = NO_ERROR;
status = mRequestStatePool.acquireItem(state);
if (status != NO_ERROR) {
LOGE("Failed to acquire free request state struct - BUG");
/*
* This should not happen since AAL is holding clients to send more
* requests than we can take
*/
return UNKNOWN_ERROR;
}
status = mCaptureUnitSettingsPool.acquireItem(state->captureSettings);
if (status != NO_ERROR) {
LOGE("Failed to acquire free CapU settings struct - BUG");
/*
* This should not happen since AAL is holding clients to send more
* requests than we can take
*/
return UNKNOWN_ERROR;
}
// set a unique ID for the settings
state->captureSettings->settingsIdentifier = systemTime();
status = mProcUnitSettingsPool.acquireItem(state->processingSettings);
if (status != NO_ERROR) {
LOGE("Failed to acquire free ProcU settings struct - BUG");
/*
* This should not happen since AAL is holding clients to send more
* requests than we can take
*/
return UNKNOWN_ERROR;
}
return OK;
}
/**
* processRequest
*
* Acquire the control structure to keep the state of the request in the control
* unit and send the message to be handled in the internal message thread.
*/
status_t
ControlUnit::processRequest(Camera3Request* request)
{
status_t status = NO_ERROR;
std::shared_ptr<RequestCtrlState> state;
LOG2("@%s: id %d", __FUNCTION__, request->getId());
status = acquireRequestStateStruct(state);
if (CC_UNLIKELY(status != OK) || CC_UNLIKELY(state.get() == nullptr)) {
return status; // error log already done in the helper method
}
state->init(request);
base::Callback<status_t()> closure =
base::Bind(&ControlUnit::handleNewRequest, base::Unretained(this),
base::Passed(std::move(state)));
mCameraThread.PostTaskAsync<status_t>(FROM_HERE, closure);
return OK;
}
status_t ControlUnit::handleNewRequest(std::shared_ptr<RequestCtrlState> state)
{
HAL_TRACE_CALL(CAMERA_DEBUG_LOG_LEVEL2, LOG_TAG);
status_t status = NO_ERROR;
std::shared_ptr<RequestCtrlState> reqState = state;
/**
* PHASE 1: Process the settings
* In this phase we analyze the request's metadata settings and convert them
* into either:
* - input parameters for 3A algorithms
* - parameters used for SoC sensors
* - Capture Unit settings
* - Processing Unit settings
*/
const android::CameraMetadata *reqSettings = reqState->request->getSettings();
CheckAndCallbackError(reqSettings == nullptr, mErrCb, UNKNOWN_ERROR,
"@%s: no settings in request", __FUNCTION__);
status = mSettingsProcessor->processRequestSettings(*reqSettings, *reqState);
if (status != NO_ERROR) {
LOGE("Could not process all settings, reporting request as invalid");
}
mPendingRequests.push_back(reqState);
reqState = mPendingRequests[0];
/**
* PHASE2: Process for capture or Q or reprocessing
* Use dummy stats if no stats is received.
*
* Use the latest valid stats for still capture,
* it comes from video pipe (during still preview).
*
* Holding request if there is enough requests processing in CIO2
* when has VIDEO pipe.
*/
if ((mLatestRequestId > PENDING_REQUEST_FOR_AWB_CONVERGENCE &&
mWaitingForCapture.size() < MAX_CIO2_PROCESSING_REQUEST_NUM) ||
mLatestRequestId == -1 ||
!mImguUnit->hasVideoPipe() ||
(mLatestStatistics != nullptr &&
mLatestRequestId == mLatestStatistics->id)) {
mPendingRequests.erase(mPendingRequests.begin());
status = processRequestForCapture(reqState, mLatestStatistics);
CheckAndCallbackError(status != OK, mErrCb, status,
"@%s: Failed to process req %d for capture",
__FUNCTION__, reqState->request->getId());
}
return status;
}
/**
* processRequestForCapture
*
* Run 3A algorithms and send the results to capture unit for capture
*
* This is the second phase in the request processing flow.
*
* The request settings have been processed in the first phase
*
* If this step is successful the request will be moved to the
* mWaitingForCapture waiting for the pixel buffers.
*/
status_t
ControlUnit::processRequestForCapture(std::shared_ptr<RequestCtrlState> &reqState,
std::shared_ptr<IPU3CapturedStatistics> &stats)
{
status_t status = NO_ERROR;
if (CC_UNLIKELY(reqState.get() == nullptr)) {
LOGE("Invalid parameters passed- request not captured - BUG");
return BAD_VALUE;
}
if (CC_UNLIKELY(reqState->captureSettings.get() == nullptr)) {
LOGE("capture Settings not given - BUG");
return BAD_VALUE;
}
/* Write the dump flag into capture settings, so that the PAL dump can be
* done all the way down at PgParamAdaptor. For the time being, only dump
* during jpeg captures.
*/
reqState->processingSettings->dump =
LogHelper::isDumpTypeEnable(CAMERA_DUMP_RAW) &&
reqState->request->getBufferCountOfFormat(HAL_PIXEL_FORMAT_BLOB) > 0;
// dump the PAL run from ISA also
reqState->captureSettings->dump = reqState->processingSettings->dump;
int reqId = reqState->request->getId();
if (stats != nullptr) {
prepareStats(*reqState, *stats.get());
LOG2("%s, stats frame sequence %u", __FUNCTION__, stats->frameSequence);
}
bool forceUpdated = (mLatestRequestId < 0 ? true : false);
status = m3ARunner->run2A(*reqState, forceUpdated);
if (status != NO_ERROR) {
LOGE("Error in running run2AandCapture for request %d", reqId);
return status;
}
mMetadata->writeLSCMetadata(reqState);
m3ARunner->runAf(*reqState);
// Latest results are saved for the next frame calculation if we do not
// find the correct results.
// TODO: Remove this once we fix the request flow so we can use the results
// from the request at prepareStats
m3aWrapper->deepCopyAiqResults(m3ARunner->getLatestResults(),
reqState->captureSettings->aiqResults,
true);
m3ARunner->updateInputParams(reqState->aiqInputParams);
status = mCaptureUnit->doCapture(reqState->request,
reqState->captureSettings);
if (CC_UNLIKELY(status != NO_ERROR)) {
LOGE("Failed to issue capture request for id %d", reqId);
}
/**
* Move the request to the vector mWaitingForCapture
*/
mWaitingForCapture.insert(std::make_pair(reqId, reqState));
mLatestRequestId = reqId;
/*
* Store the settings in the settings history if we expect stats to be in
* use. This is only in case the control mode is different than
* ANDROID_CONTROL_MODE_OFF_KEEP_STATE
* WA - HAL runs out of capture settings in ANDROID_CONTROL_MODE_OFF,
* so history is not udated for it. TODO fix later so that 3A runs in
* background without actually applying the settings.
*/
if (reqState->aaaControls.controlMode != ANDROID_CONTROL_MODE_OFF_KEEP_STATE &&
reqState->aaaControls.controlMode != ANDROID_CONTROL_MODE_OFF) {
// Keep the size of the history fixed
if (mSettingsHistory.size() >= MAX_SETTINGS_HISTORY_SIZE) {
LOGP("%s delete one hold for %p in mCaptureUnitSettingsPool",
__FUNCTION__, mSettingsHistory.begin()->get());
mSettingsHistory.erase(mSettingsHistory.begin());
}
mSettingsHistory.push_back(reqState->captureSettings);
LOGP("%s add one hold for %p in mCaptureUnitSettingsPool",
__FUNCTION__, reqState->captureSettings.get());
}
int jpegBufCount = reqState->request->getBufferCountOfFormat(HAL_PIXEL_FORMAT_BLOB);
int implDefinedBufCount = reqState->request->getBufferCountOfFormat(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED);
int yuv888BufCount = reqState->request->getBufferCountOfFormat(HAL_PIXEL_FORMAT_YCbCr_420_888);
LOG2("@%s jpegs:%d impl defined:%d yuv888:%d inputbufs:%d req id %d",
__FUNCTION__,
jpegBufCount,
implDefinedBufCount,
yuv888BufCount,
(reqState->request->hasInputBuf() ? 1 : 0),
reqState->request->getId());
if (jpegBufCount > 0) {
// NOTE: Makernote should be get after isp_bxt_run()
// NOTE: makernote.data deleted in JpegEncodeTask::handleMakernote()
const unsigned mknSize = MAKERNOTE_SECTION1_SIZE + MAKERNOTE_SECTION2_SIZE;
MakernoteData mkn = {nullptr, mknSize};
mkn.data = new char[mknSize];
m3aWrapper->getMakerNote(ia_mkn_trg_section_2, mkn);
reqState->captureSettings->makernote = mkn;
} else {
// No JPEG buffers in request. Reset MKN info, just in case.
reqState->captureSettings->makernote.data = nullptr;
reqState->captureSettings->makernote.size = 0;
}
return status;
}
status_t ControlUnit::handleNewImage(MessageNewImage msg)
{
HAL_TRACE_CALL(CAMERA_DEBUG_LOG_LEVEL2, LOG_TAG);
int reqId = msg.requestId;
std::map<int, std::shared_ptr<RequestCtrlState>>::iterator it =
mWaitingForCapture.find(reqId);
CheckAndCallbackError(it == mWaitingForCapture.end(), mErrCb, UNKNOWN_ERROR,
"@%s, Unexpected new image received %d", __FUNCTION__, reqId);
std::shared_ptr<RequestCtrlState> reqState = it->second;
CheckAndCallbackError(reqState == nullptr, mErrCb, UNKNOWN_ERROR,
"@%s, State for request Id = %d is nullptr", __FUNCTION__, reqId);
/*
* Send the buffer. See complete processing to understand
* how we do the hold up.
*/
reqState->captureBufs.rawBuffer = nullptr;
reqState->captureBufs.rawNonScaledBuffer = nullptr;
reqState->captureBufs.lastRawNonScaledBuffer = nullptr;
reqState->framesArrived++;
CheckAndCallbackError(msg.type != CAPTURE_EVENT_RAW_BAYER, mErrCb, UNKNOWN_ERROR,
"@%s, Unknown capture buffer type in request %d", __FUNCTION__, reqId);
reqState->captureBufs.rawNonScaledBuffer = msg.rawBuffer;
reqState->captureBufs.lastRawNonScaledBuffer = msg.lastRawBuffer;
status_t status = completeProcessing(reqState);
CheckAndCallbackError(status != OK, mErrCb, status,
"@%s, Cannot complete the buffer processing", __FUNCTION__);
return OK;
}
status_t ControlUnit::handleNewStat(MessageStats msg)
{
HAL_TRACE_CALL(CAMERA_DEBUG_LOG_LEVEL2, LOG_TAG);
status_t status = NO_ERROR;
std::shared_ptr<IPU3CapturedStatistics> stats = msg.stats;
int statsId = 0;
if (stats.get() != nullptr) {
statsId = stats->id;
// Still pipe has no stats output and data is invalid
// so here only valid data are saved.
if (stats->rgbsGridArray[0] && stats->rgbsGridArray[0]->grid_width)
mLatestStatistics = stats;
}
if (mPendingRequests.empty()) {
return status;
}
// If enough requests are processing, don't need to process next request.
if (mWaitingForCapture.size() >= MAX_CIO2_PROCESSING_REQUEST_NUM) {
return NO_ERROR;
}
size_t reqCount = 1;
if (statsId == mLatestRequestId && mLatestRequestId >= PENDING_REQUEST_FOR_AWB_CONVERGENCE) {
// The 0 ~ PENDING_REQUEST_FOR_AWB_CONVERGENCE request will run with new statistics to speed
// AWB converging process. Otherwise, queue all pending requests to CIO2.
reqCount = MAX_CIO2_PROCESSING_REQUEST_NUM;
}
// Process request
for (size_t i = 0; i < reqCount && !mPendingRequests.empty(); i++) {
std::shared_ptr<RequestCtrlState> reqState = mPendingRequests[0];
mPendingRequests.erase(mPendingRequests.begin());
CheckAndCallbackError((!reqState || reqState->request == nullptr), mErrCb,
UNKNOWN_ERROR, "@%s, reqState is nullptr, find BUG!", __FUNCTION__);
LOG2("@%s: process reqState %d", __FUNCTION__, reqState->request->getId());
status = processRequestForCapture(reqState, mLatestStatistics);
CheckAndCallbackError(status != OK, mErrCb, status,
"@%s: Failed to process request %d for capture",
__FUNCTION__, reqState->request->getId());
}
return status;
}
/**
* completeProcessing
*
* Forward the pixel buffer to the Processing Unit to complete the processing.
* If all the buffers from Capture Unit have arrived then:
* - it updates the metadata
* - it removes the request from the vector mWaitingForCapture.
*
* The metadata update is now transferred to the ProcessingUnit.
* This is done only on arrival of the last pixel data buffer. ControlUnit still
* keeps the state, so it is responsible for triggering the update.
*/
status_t
ControlUnit::completeProcessing(std::shared_ptr<RequestCtrlState> &reqState)
{
HAL_TRACE_CALL(CAMERA_DEBUG_LOG_LEVEL2, LOG_TAG);
int reqId = reqState->captureSettings->aiqResults.requestId;
bool updateMeta = false;
LOG2("complete processing req %d frames arrived %d",
reqId, reqState->framesArrived);
// We do this only once per request when the first buffer arrives
if (reqState->framesArrived == 1) {
mMetadata->writeAwbMetadata(*reqState);
mMetadata->writeSensorMetadata(*reqState);
mMetadata->writePAMetadata(*reqState);
mMetadata->writeJpegMetadata(*reqState);
mMetadata->writeMiscMetadata(*reqState);
mMetadata->writeLensMetadata(*reqState);
mMetadata->fillTonemapCurve(*reqState);
int64_t rollingShutterSkew = mCaptureUnit->getRollingShutterSkew();
//# ANDROID_METADATA_Dynamic android.sensor.rollingShutterSkew done
reqState->ctrlUnitResult->update(ANDROID_SENSOR_ROLLING_SHUTTER_SKEW,
&rollingShutterSkew, 1);
uint8_t pipelineDepth = mCaptureUnit->getPipelineDepth();
//# ANDROID_METADATA_Dynamic android.request.pipelineDepth done
reqState->ctrlUnitResult->update(ANDROID_REQUEST_PIPELINE_DEPTH,
&pipelineDepth, 1);
}
updateMeta = true;
mWaitingForCapture.erase(reqId);
if (CC_LIKELY((reqState->request != nullptr) &&
(reqState->captureSettings.get() != nullptr))) {
LOG2("%s: completing buffer %d for request %d",
__FUNCTION__,
reqState->framesArrived,
reqId);
/* TODO: cleanup
* This struct copy from state is only needed for JPEG creation.
* Ideally we should directly write inside members of processingSettings
* whatever settings are needed for Processing Unit.
* This should be moved to any of the processXXXSettings.
*/
reqState->processingSettings->android3Actrl = reqState->aaaControls;
mImguUnit->completeRequest(reqState->processingSettings,
reqState->captureBufs,
updateMeta);
} else {
LOGE("request or captureSetting is nullptr - Fix the bug!");
return UNKNOWN_ERROR;
}
return NO_ERROR;
}
status_t ControlUnit::handleNewShutter(MessageShutter msg)
{
HAL_TRACE_CALL(CAMERA_DEBUG_LOG_LEVEL2, LOG_TAG);
std::shared_ptr<RequestCtrlState> reqState = nullptr;
int reqId = msg.requestId;
std::map<int, std::shared_ptr<RequestCtrlState>>::iterator it =
mWaitingForCapture.find(reqId);
if (it == mWaitingForCapture.end()) {
LOGE("Unexpected shutter event received for request %d - Fix the bug", reqId);
return UNKNOWN_ERROR;
}
reqState = it->second;
if (CC_UNLIKELY(reqState.get() == nullptr || reqState->captureSettings.get() == nullptr)) {
LOGE("No valid state or settings for request Id = %d"
"- Fix the bug!", reqId);
return UNKNOWN_ERROR;
}
/* flash state - hack, should know from frame whether it fired */
const android::CameraMetadata* metaData = reqState->request->getSettings();
if (metaData == nullptr) {
LOGE("Metadata should not be nullptr. Fix the bug!");
return UNKNOWN_ERROR;
}
uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE;
//# ANDROID_METADATA_Dynamic android.flash.state done
reqState->ctrlUnitResult->update(ANDROID_FLASH_STATE, &flashState, 1);
int64_t ts = msg.tv_sec * 1000000000; // seconds to nanoseconds
ts += msg.tv_usec * 1000; // microseconds to nanoseconds
//use request setting timestamp when reprocess
if (reqState->request->hasInputBuf()){
camera_metadata_ro_entry entry;
entry = metaData->find(ANDROID_SENSOR_TIMESTAMP);
if (entry.count == 1) {
ts = entry.data.i64[0];
}
}
//# ANDROID_METADATA_Dynamic android.sensor.timestamp done
reqState->ctrlUnitResult->update(ANDROID_SENSOR_TIMESTAMP, &ts, 1);
reqState->request->mCallback->shutterDone(reqState->request, ts);
reqState->shutterDone = true;
reqState->captureSettings->timestamp = ts;
return NO_ERROR;
}
status_t ControlUnit::handleNewSensorDescriptor(MessageSensorMode msg)
{
HAL_TRACE_CALL(CAMERA_DEBUG_LOG_LEVEL1, LOG_TAG);
mMetadata->FillSensorDescriptor(msg);
return mSettingsProcessor->handleNewSensorDescriptor(msg);
}
status_t
ControlUnit::flush(void)
{
HAL_TRACE_CALL(CAMERA_DEBUG_LOG_LEVEL2, LOG_TAG);
status_t status = NO_ERROR;
base::Callback<status_t()> closure =
base::Bind(&ControlUnit::handleFlush, base::Unretained(this));
mCameraThread.PostTaskSync<status_t>(FROM_HERE, closure, &status);
return status;
}
status_t ControlUnit::handleFlush(void)
{
HAL_TRACE_CALL(CAMERA_DEBUG_LOG_LEVEL2, LOG_TAG);
mWaitingForCapture.clear();
mPendingRequests.clear();
mSettingsHistory.clear();
return NO_ERROR;
}
bool
ControlUnit::notifyCaptureEvent(CaptureMessage *captureMsg)
{
HAL_TRACE_CALL(CAMERA_DEBUG_LOG_LEVEL2, LOG_TAG);
if (captureMsg == nullptr) {
return false;
}
if (captureMsg->id == CAPTURE_MESSAGE_ID_ERROR) {
// handle capture error
return true;
}
switch (captureMsg->data.event.type) {
case CAPTURE_EVENT_RAW_BAYER:
{
MessageNewImage msg;
msg.type = CAPTURE_EVENT_RAW_BAYER;
msg.requestId = captureMsg->data.event.reqId;
msg.rawBuffer = captureMsg->data.event.pixelBuffer;
msg.lastRawBuffer = captureMsg->data.event.lastPixelBuffer;
base::Callback<status_t()> closure =
base::Bind(&ControlUnit::handleNewImage,
base::Unretained(this),
base::Passed(std::move(msg)));
mCameraThread.PostTaskAsync<status_t>(FROM_HERE, closure);
break;
}
case CAPTURE_EVENT_NEW_SENSOR_DESCRIPTOR:
{
MessageSensorMode msg;
msg.exposureDesc = captureMsg->data.event.exposureDesc;
msg.frameParams = captureMsg->data.event.frameParams;
base::Callback<status_t()> closure =
base::Bind(&ControlUnit::handleNewSensorDescriptor,
base::Unretained(this),
base::Passed(std::move(msg)));
mCameraThread.PostTaskAsync<status_t>(FROM_HERE, closure);
break;
}
case CAPTURE_EVENT_2A_STATISTICS:
if (CC_UNLIKELY(captureMsg->data.event.stats.get() == nullptr)) {
LOGE("captureMsg->stats == nullptr");
return false;
} else {
MessageStats msg;
msg.stats = captureMsg->data.event.stats;
base::Callback<status_t()> closure =
base::Bind(&ControlUnit::handleNewStat,
base::Unretained(this),
base::Passed(std::move(msg)));
mCameraThread.PostTaskAsync<status_t>(FROM_HERE, closure);
}
break;
case CAPTURE_EVENT_SHUTTER:
{
MessageShutter msg;
msg.requestId = captureMsg->data.event.reqId;
msg.tv_sec = captureMsg->data.event.timestamp.tv_sec;
msg.tv_usec = captureMsg->data.event.timestamp.tv_usec;
base::Callback<status_t()> closure =
base::Bind(&ControlUnit::handleNewShutter,
base::Unretained(this),
base::Passed(std::move(msg)));
mCameraThread.PostTaskAsync<status_t>(FROM_HERE, closure);
break;
}
case CAPTURE_EVENT_NEW_SOF:
{
std::lock_guard<std::mutex> l(mSofDataLock);
if (mSofDataMap.size() >= MAX_SETTINGS_HISTORY_SIZE) {
mSofDataMap.erase(mSofDataMap.begin());
}
mSofDataMap[captureMsg->data.event.sequence] =
captureMsg->data.event.timestamp.tv_sec * 1000000
+ captureMsg->data.event.timestamp.tv_usec;
LOG2("sof event sequence = %u", captureMsg->data.event.sequence);
break;
}
default:
LOGW("Unsupported Capture event ");
break;
}
return true;
}
/**
* prepareStats
*
* Prepares the ia_aiq_statistics_input_params struct before running 3A and then
* it calls Intel3Aplus::setStatistics() to pass them to the 3A algorithms.
*
* The main preparation consist in finding the capture unit settings that were
* in effect when the statistics where captured.
*
* The AIQ results in effect when the statistics were gathered are available in
* the control unit
* TODO: Current flow is not handling these results well. We may have completed
* the request and the results are lost. We need to keep the capture settings
* alive longer than the request state struct. This was done in Sofia.
*
* Alternatively once we have EmDa we can also use that.
*
* \param reqState [IN/OUT]: request to process
* \param s [OUT]: structure holding the captured stats
*/
void ControlUnit::prepareStats(RequestCtrlState &reqState,
IPU3CapturedStatistics &s)
{
status_t status = NO_ERROR;
std::shared_ptr<CaptureUnitSettings> settingsInEffect = nullptr;
LOG2(" %s: statistics from request %d used to process request %d",
__FUNCTION__, s.id,
reqState.request->getId());
// Prepare the input parameters for the statistics
ia_aiq_statistics_input_params* params = &s.aiqStatsInputParams;
params->camera_orientation = ia_aiq_camera_orientation_unknown;
params->external_histograms = nullptr;
params->num_external_histograms = 0;
settingsInEffect = findSettingsInEffect(params->frame_id);
if (settingsInEffect.get()) {
params->frame_ae_parameters = &settingsInEffect->aiqResults.aeResults;
params->frame_af_parameters = &settingsInEffect->aiqResults.afResults;
params->awb_results = &settingsInEffect->aiqResults.awbResults;
params->frame_sa_parameters = &settingsInEffect->aiqResults.saResults;
params->frame_pa_parameters = &settingsInEffect->aiqResults.paResults;
} else {
LOG1("preparing statistics from exp %lld that we do not track", params->frame_id);
// default to latest results
AiqResults& latestResults = m3ARunner->getLatestResults();
params->frame_ae_parameters = &latestResults.aeResults;
params->frame_af_parameters = &latestResults.afResults;
params->awb_results = &latestResults.awbResults;
params->frame_sa_parameters = &latestResults.saResults;
params->frame_pa_parameters = &latestResults.paResults;
}
unsigned long long sofTimestamp = 0;
{
std::lock_guard<std::mutex> l(mSofDataLock);
if (mSofDataMap.find(params->frame_id) != mSofDataMap.end()) {
sofTimestamp = mSofDataMap.at(params->frame_id);
} else {
LOG2("frame timestamp %llu us, rolling shutter time %ld us", params->frame_timestamp,
mCaptureUnit->getRollingShutterSkew() / 1000);
sofTimestamp = params->frame_timestamp - mCaptureUnit->getRollingShutterSkew() / 1000;
}
}
params->frame_timestamp = sofTimestamp
- params->frame_ae_parameters->exposures[0].exposure->exposure_time_us;
LOG2("frame expo start timestamp %lld, sequence %llu", params->frame_timestamp,
params->frame_id);
ia_face faces[MAX_FACES_DETECTABLE] = {};
ia_face_state facesState;
if (mFaceEngine && mFaceEngine->getMode() != FD_MODE_OFF) {
facesState.num_faces = 0;
facesState.faces = faces;
int ret = mFaceEngine->getResult(&facesState);
if (ret == OK && facesState.num_faces > 0) {
params->faces = &facesState;
} else {
params->faces = nullptr;
}
LOG2("@%s, face number:%d", __FUNCTION__, facesState.num_faces);
CVFaceEngineAbstractResult fdResult;
ret = mFaceEngine->getResult(&fdResult);
if (ret == OK) {
mMetadata->writeFDMetadata(reqState, fdResult);
}
}
/**
* Pass stats to all 3A algorithms
* Since at the moment we do not have separate events for AF and AA stats
* there is no need to pass the stats per algorithm.
* AF usually runs first, but not always. For that reason we pass the stats
* to the AIQ algorithms here.
*/
status = m3aWrapper->setStatistics(params);
if (CC_UNLIKELY(status != OK)) {
LOGW("Failed to set statistics for 3A iteration");
}
// algo's are ready to run
reqState.afState = ALGORITHM_READY;
reqState.aeState = ALGORITHM_READY;
reqState.awbState = ALGORITHM_READY;
}
/**
*
* find the capture unit settings that were in effect for the frame with
* exposure id (expId) was captured.
*
* Iterates through the vector settings history to find the settings marked as
* in effect in an exposure id that is the same or bigger.
*
* It keeps the size of the settings history buffer limited.
*/
std::shared_ptr<CaptureUnitSettings> ControlUnit::findSettingsInEffect(uint64_t expId)
{
std::shared_ptr<CaptureUnitSettings> settingsInEffect = nullptr;
std::deque<std::shared_ptr<CaptureUnitSettings>>::iterator it;
for (it = mSettingsHistory.begin(); it != mSettingsHistory.end(); ++it) {
if ((*it)->inEffectFrom == expId) {
// we found the exact settings
settingsInEffect = *it;
break;
}
if ((*it)->inEffectFrom > expId && it != mSettingsHistory.begin()) {
// Pick the previous settings which have had effect already.
// "it" is not the history begin so "it--" is safe.
it--;
settingsInEffect = *it;
break;
}
}
if (it == mSettingsHistory.end() && !mSettingsHistory.empty()) {
LOG2("Could not find settings for expID %" PRIu64 " providing for %d", expId,
mSettingsHistory[0]->inEffectFrom);
settingsInEffect = mSettingsHistory[0];
}
return settingsInEffect;
}
} // namespace intel
} // namespace cros