/*
* x3a_analyzer_simple.cpp - a simple 3a analyzer
*
* Copyright (c) 2015 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.
*
* Author: Wind Yuan <feng.yuan@intel.com>
*/
#include "x3a_analyzer_simple.h"
namespace XCam {
#define SIMPLE_MIN_TARGET_EXPOSURE_TIME 5000 //5ms
#define SIMPLE_MAX_TARGET_EXPOSURE_TIME 33000 //33ms
#define SIMPLE_DEFAULT_BLACK_LEVEL 0.05
class SimpleAeHandler
: public AeHandler
{
public:
SimpleAeHandler (X3aAnalyzerSimple *analyzer)
: _analyzer (analyzer)
{}
~SimpleAeHandler () {}
virtual XCamReturn analyze (X3aResultList &output) {
return _analyzer->analyze_ae (output);
}
private:
X3aAnalyzerSimple *_analyzer;
};
class SimpleAwbHandler
: public AwbHandler
{
public:
SimpleAwbHandler (X3aAnalyzerSimple *analyzer)
: _analyzer (analyzer)
{}
~SimpleAwbHandler () {}
virtual XCamReturn analyze (X3aResultList &output) {
return _analyzer->analyze_awb (output);
}
private:
X3aAnalyzerSimple *_analyzer;
};
class SimpleAfHandler
: public AfHandler
{
public:
SimpleAfHandler (X3aAnalyzerSimple *analyzer)
: _analyzer (analyzer)
{}
~SimpleAfHandler () {}
virtual XCamReturn analyze (X3aResultList &output) {
return _analyzer->analyze_af (output);
}
private:
X3aAnalyzerSimple *_analyzer;
};
class SimpleCommonHandler
: public CommonHandler
{
public:
SimpleCommonHandler (X3aAnalyzerSimple *analyzer)
: _analyzer (analyzer)
{}
~SimpleCommonHandler () {}
virtual XCamReturn analyze (X3aResultList &output) {
XCAM_UNUSED (output);
return XCAM_RETURN_NO_ERROR;
}
private:
X3aAnalyzerSimple *_analyzer;
};
X3aAnalyzerSimple::X3aAnalyzerSimple ()
: X3aAnalyzer ("X3aAnalyzerSimple")
, _last_target_exposure ((double)SIMPLE_MIN_TARGET_EXPOSURE_TIME)
, _is_ae_started (false)
, _ae_calculation_interval (0)
{
}
X3aAnalyzerSimple::~X3aAnalyzerSimple ()
{
}
SmartPtr<AeHandler>
X3aAnalyzerSimple::create_ae_handler ()
{
SimpleAeHandler *handler = new SimpleAeHandler (this);
return handler;
}
SmartPtr<AwbHandler>
X3aAnalyzerSimple::create_awb_handler ()
{
SimpleAwbHandler *handler = new SimpleAwbHandler (this);
return handler;
}
SmartPtr<AfHandler>
X3aAnalyzerSimple::create_af_handler ()
{
SimpleAfHandler *handler = new SimpleAfHandler (this);
return handler;
}
SmartPtr<CommonHandler>
X3aAnalyzerSimple::create_common_handler ()
{
SimpleCommonHandler *handler = new SimpleCommonHandler (this);
return handler;
}
XCamReturn
X3aAnalyzerSimple::configure_3a ()
{
_is_ae_started = false;
_ae_calculation_interval = 0;
return XCAM_RETURN_NO_ERROR;
}
XCamReturn
X3aAnalyzerSimple::pre_3a_analyze (SmartPtr<X3aStats> &stats)
{
_current_stats = stats;
return XCAM_RETURN_NO_ERROR;
}
XCamReturn
X3aAnalyzerSimple::post_3a_analyze (X3aResultList &results)
{
_current_stats.release ();
XCam3aResultBlackLevel black_level;
SmartPtr<X3aBlackLevelResult> bl_result = new X3aBlackLevelResult (XCAM_3A_RESULT_BLACK_LEVEL);
xcam_mem_clear (black_level);
black_level.r_level = SIMPLE_DEFAULT_BLACK_LEVEL;
black_level.gr_level = SIMPLE_DEFAULT_BLACK_LEVEL;
black_level.gb_level = SIMPLE_DEFAULT_BLACK_LEVEL;
black_level.b_level = SIMPLE_DEFAULT_BLACK_LEVEL;
bl_result->set_standard_result (black_level);
results.push_back (bl_result);
return XCAM_RETURN_NO_ERROR;
}
XCamReturn
X3aAnalyzerSimple::analyze_awb (X3aResultList &output)
{
const XCam3AStats *stats = _current_stats->get_stats ();
double sum_r = 0.0, sum_gr = 0.0, sum_gb = 0.0, sum_b = 0.0;
double avg_r = 0.0, avg_gr = 0.0, avg_gb = 0.0, avg_b = 0.0;
double target_avg = 0.0;
XCam3aResultWhiteBalance wb;
xcam_mem_clear (wb);
XCAM_ASSERT (stats);
// calculate avg r, gr, gb, b
for (uint32_t i = 0; i < stats->info.height; ++i)
for (uint32_t j = 0; j < stats->info.width; ++j) {
sum_r += (double)(stats->stats[i * stats->info.aligned_width + j].avg_r);
sum_gr += (double)(stats->stats[i * stats->info.aligned_width + j].avg_gr);
sum_gb += (double)(stats->stats[i * stats->info.aligned_width + j].avg_gb);
sum_b += (double)(stats->stats[i * stats->info.aligned_width + j].avg_b);
}
avg_r = sum_r / (stats->info.width * stats->info.height);
avg_gr = sum_gr / (stats->info.width * stats->info.height);
avg_gb = sum_gb / (stats->info.width * stats->info.height);
avg_b = sum_b / (stats->info.width * stats->info.height);
target_avg = (avg_gr + avg_gb) / 2;
wb.r_gain = target_avg / avg_r;
wb.b_gain = target_avg / avg_b;
wb.gr_gain = 1.0;
wb.gb_gain = 1.0;
SmartPtr<X3aWhiteBalanceResult> result = new X3aWhiteBalanceResult (XCAM_3A_RESULT_WHITE_BALANCE);
result->set_standard_result (wb);
output.push_back (result);
XCAM_LOG_DEBUG ("X3aAnalyzerSimple analyze awb, r:%f, gr:%f, gb:%f, b:%f",
wb.r_gain, wb.gr_gain, wb.gb_gain, wb.b_gain);
return XCAM_RETURN_NO_ERROR;
}
XCamReturn
X3aAnalyzerSimple::analyze_ae (X3aResultList &output)
{
static const uint32_t expect_y_mean = 110;
const XCam3AStats *stats = _current_stats->get_stats ();
XCAM_FAIL_RETURN(
WARNING,
stats,
XCAM_RETURN_ERROR_UNKNOWN,
"failed to get XCam3AStats");
double sum_y = 0.0;
double target_exposure = 1.0;
SmartPtr<X3aExposureResult> result = new X3aExposureResult (XCAM_3A_RESULT_EXPOSURE);
XCam3aResultExposure exposure;
xcam_mem_clear (exposure);
exposure.digital_gain = 1.0;
if (!_is_ae_started) {
_last_target_exposure = SIMPLE_MIN_TARGET_EXPOSURE_TIME;
exposure.exposure_time = _last_target_exposure;
exposure.analog_gain = 1.0;
result->set_standard_result (exposure);
output.push_back (result);
_is_ae_started = true;
return XCAM_RETURN_NO_ERROR;
}
if (_ae_calculation_interval % 10 == 0) {
for (uint32_t i = 0; i < stats->info.height; ++i)
for (uint32_t j = 0; j < stats->info.width; ++j) {
sum_y += (double)(stats->stats[i * stats->info.aligned_width + j].avg_y);
}
sum_y /= (stats->info.width * stats->info.height);
target_exposure = (expect_y_mean / sum_y) * _last_target_exposure;
target_exposure = XCAM_MAX (target_exposure, SIMPLE_MIN_TARGET_EXPOSURE_TIME);
if (target_exposure > SIMPLE_MAX_TARGET_EXPOSURE_TIME * 255)
target_exposure = SIMPLE_MAX_TARGET_EXPOSURE_TIME * 255;
if (target_exposure > SIMPLE_MAX_TARGET_EXPOSURE_TIME) {
exposure.exposure_time = SIMPLE_MAX_TARGET_EXPOSURE_TIME;
exposure.analog_gain = target_exposure / exposure.exposure_time;
} else {
exposure.exposure_time = target_exposure;
exposure.analog_gain = 1.0;
}
result->set_standard_result (exposure);
output.push_back (result);
_last_target_exposure = target_exposure;
}
_ae_calculation_interval++;
return XCAM_RETURN_NO_ERROR;
}
XCamReturn X3aAnalyzerSimple::analyze_af (X3aResultList &output)
{
XCAM_UNUSED (output);
return XCAM_RETURN_NO_ERROR;
}
};