/*
|
* 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;
|
}
|
|
};
|