blob: 50b8309833b6b1c331fd081ae5e0dc9338c0a5f8 [file] [log] [blame]
/*
* aiq_handler.cpp - AIQ handler
*
* Copyright (c) 2012-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>
* Author: Yan Zhang <yan.y.zhang@intel.com>
*/
#include "aiq_handler.h"
#include "x3a_isp_config.h"
#include <string.h>
#include <math.h>
#include "ia_isp_2_2.h"
#define MAX_STATISTICS_WIDTH 150
#define MAX_STATISTICS_HEIGHT 150
namespace XCam {
struct IspInputParameters {
ia_aiq_frame_use frame_use;
ia_aiq_frame_params *sensor_frame_params;
ia_aiq_exposure_parameters *exposure_results;
ia_aiq_awb_results *awb_results;
ia_aiq_gbce_results *gbce_results;
ia_aiq_pa_results *pa_results;
int8_t manual_brightness;
int8_t manual_contrast;
int8_t manual_hue;
int8_t manual_saturation;
int8_t manual_sharpness;
int8_t manual_nr_level;
ia_isp_effect effects;
IspInputParameters ()
: frame_use (ia_aiq_frame_use_preview)
, sensor_frame_params (NULL)
, exposure_results (NULL)
, awb_results (NULL)
, gbce_results (NULL)
, pa_results (NULL)
, manual_brightness (0)
, manual_contrast (0)
, manual_hue (0)
, manual_saturation (0)
, manual_sharpness (0)
, manual_nr_level (0)
, effects (ia_isp_effect_none)
{}
};
class IaIspAdaptor22
: public IaIspAdaptor
{
public:
IaIspAdaptor22 () {
xcam_mem_clear (&_input_params);
}
~IaIspAdaptor22 () {
if (_handle)
ia_isp_2_2_deinit (_handle);
}
virtual bool init (
const ia_binary_data *cpf,
unsigned int max_width,
unsigned int max_height,
ia_cmc_t *cmc,
ia_mkn *mkn);
virtual bool convert_statistics (
void *statistics,
ia_aiq_rgbs_grid **out_rgbs_grid,
ia_aiq_af_grid **out_af_grid);
virtual bool run (
const IspInputParameters *isp_input_params,
ia_binary_data *output_data);
private:
ia_isp_2_2_input_params _input_params;
};
bool
IaIspAdaptor22::init (
const ia_binary_data *cpf,
unsigned int max_width,
unsigned int max_height,
ia_cmc_t *cmc,
ia_mkn *mkn)
{
xcam_mem_clear (&_input_params);
_input_params.isp_vamem_type = 1;
_handle = ia_isp_2_2_init (cpf, max_width, max_height, cmc, mkn);
XCAM_FAIL_RETURN (ERROR, _handle, false, "ia_isp 2.2 init failed");
return true;
}
bool
IaIspAdaptor22::convert_statistics (
void *statistics,
ia_aiq_rgbs_grid **out_rgbs_grid,
ia_aiq_af_grid **out_af_grid)
{
ia_err err;
err = ia_isp_2_2_statistics_convert (_handle, statistics, out_rgbs_grid, out_af_grid);
XCAM_FAIL_RETURN (ERROR, err == ia_err_none, false, "ia_isp 2.2 convert stats failed");
return true;
}
bool
IaIspAdaptor22::run (
const IspInputParameters *isp_input_params,
ia_binary_data *output_data)
{
ia_err err;
_input_params.frame_use = isp_input_params->frame_use;
_input_params.sensor_frame_params = isp_input_params->sensor_frame_params;
_input_params.exposure_results = isp_input_params->exposure_results;
_input_params.awb_results = isp_input_params->awb_results;
_input_params.gbce_results = isp_input_params->gbce_results;
_input_params.pa_results = isp_input_params->pa_results;
_input_params.manual_brightness = isp_input_params->manual_brightness;
_input_params.manual_contrast = isp_input_params->manual_contrast;
_input_params.manual_hue = isp_input_params->manual_hue;
_input_params.manual_saturation = isp_input_params->manual_saturation;
_input_params.nr_setting.feature_level = ia_isp_feature_level_high;
_input_params.nr_setting.strength = isp_input_params->manual_nr_level;
_input_params.ee_setting.feature_level = ia_isp_feature_level_high;
_input_params.ee_setting.strength = isp_input_params->manual_sharpness;
_input_params.effects = isp_input_params->effects;
err = ia_isp_2_2_run (_handle, &_input_params, output_data);
XCAM_FAIL_RETURN (ERROR, err == ia_err_none, false, "ia_isp 2.2 run failed");
return true;
}
#if 0
class IaIspAdaptor15
: public IaIspAdaptor
{
public:
IaIspAdaptor15 () {
xcam_mem_clear (&_input_params);
}
~IaIspAdaptor15 () {
if (_handle)
ia_isp_1_5_deinit (_handle);
}
virtual bool init (
const ia_binary_data *cpf,
unsigned int max_width,
unsigned int max_height,
ia_cmc_t *cmc,
ia_mkn *mkn);
virtual bool convert_statistics (
void *statistics,
ia_aiq_rgbs_grid **out_rgbs_grid,
ia_aiq_af_grid **out_af_grid);
virtual bool run (
const IspInputParameters *isp_input_params,
ia_binary_data *output_data);
private:
ia_isp_1_5_input_params _input_params;
};
bool
IaIspAdaptor15::init (
const ia_binary_data *cpf,
unsigned int max_width,
unsigned int max_height,
ia_cmc_t *cmc,
ia_mkn *mkn)
{
xcam_mem_clear (&_input_params);
_input_params.isp_vamem_type = 1;
_handle = ia_isp_1_5_init (cpf, max_width, max_height, cmc, mkn);
XCAM_FAIL_RETURN (ERROR, _handle, false, "ia_isp 1.5 init failed");
return true;
}
bool
IaIspAdaptor15::convert_statistics (
void *statistics,
ia_aiq_rgbs_grid **out_rgbs_grid,
ia_aiq_af_grid **out_af_grid)
{
ia_err err;
err = ia_isp_1_5_statistics_convert (_handle, statistics, out_rgbs_grid, out_af_grid);
XCAM_FAIL_RETURN (ERROR, err == ia_err_none, false, "ia_isp 1.5 convert stats failed");
return true;
}
bool
IaIspAdaptor15::run (
const IspInputParameters *isp_input_params,
ia_binary_data *output_data)
{
ia_err err;
_input_params.frame_use = isp_input_params->frame_use;
_input_params.sensor_frame_params = isp_input_params->sensor_frame_params;
_input_params.exposure_results = isp_input_params->exposure_results;
_input_params.awb_results = isp_input_params->awb_results;
_input_params.gbce_results = isp_input_params->gbce_results;
_input_params.pa_results = isp_input_params->pa_results;
_input_params.manual_brightness = isp_input_params->manual_brightness;
_input_params.manual_contrast = isp_input_params->manual_contrast;
_input_params.manual_hue = isp_input_params->manual_hue;
_input_params.manual_saturation = isp_input_params->manual_saturation;
_input_params.nr_setting.feature_level = ia_isp_feature_level_high;
_input_params.nr_setting.strength = isp_input_params->manual_nr_level;
_input_params.ee_setting.feature_level = ia_isp_feature_level_high;
_input_params.ee_setting.strength = isp_input_params->manual_sharpness;
_input_params.effects = isp_input_params->effects;
err = ia_isp_1_5_run (_handle, &_input_params, output_data);
XCAM_FAIL_RETURN (ERROR, err == ia_err_none, false, "ia_isp 1.5 run failed");
return true;
}
#endif
static double
_calculate_new_value_by_speed (double start, double end, double speed)
{
XCAM_ASSERT (speed >= 0.0 && speed <= 1.0);
static const double value_equal_range = 0.000001;
if (fabs (end - start) <= value_equal_range)
return end;
return (start * (1.0 - speed) + end * speed);
}
static double
_imx185_sensor_gain_code_to_mutiplier (uint32_t code)
{
/* 185 sensor code : DB = 160 : 48 */
double db;
db = code * 48.0 / 160.0;
return pow (10.0, db / 20.0);
}
static uint32_t
_mutiplier_to_imx185_sensor_gain_code (double mutiplier)
{
double db = log10 (mutiplier) * 20;
if (db > 48)
db = 48;
return (uint32_t) (db * 160 / 48);
}
static uint32_t
_time_to_coarse_line (ia_aiq_exposure_sensor_descriptor *desc, uint32_t time_us)
{
float value = time_us * desc->pixel_clock_freq_mhz;
value = (value + desc->pixel_periods_per_line / 2) / desc->pixel_periods_per_line;
return (uint32_t)(value);
}
AiqAeHandler::AiqAeResult::AiqAeResult()
{
xcam_mem_clear (&ae_result);
xcam_mem_clear (&ae_exp_ret);
xcam_mem_clear (&aiq_exp_param);
xcam_mem_clear (&sensor_exp_param);
xcam_mem_clear (&weight_grid);
xcam_mem_clear (&flash_param);
}
void
AiqAeHandler::AiqAeResult::copy (ia_aiq_ae_results *result)
{
XCAM_ASSERT (result);
this->ae_result = *result;
this->aiq_exp_param = *result->exposures[0].exposure;
this->sensor_exp_param = *result->exposures[0].sensor_exposure;
this->weight_grid = *result->weight_grid;
this->flash_param = *result->flash;
this->ae_exp_ret.exposure = &this->aiq_exp_param;
this->ae_exp_ret.sensor_exposure = &this->sensor_exp_param;
this->ae_result.exposures = &this->ae_exp_ret;
this->ae_result.weight_grid = &this->weight_grid;
this->ae_result.flash = &this->flash_param;
this->ae_result.num_exposures = 1;
}
AiqAeHandler::AiqAeHandler (SmartPtr<AiqCompositor> &aiq_compositor)
: _aiq_compositor (aiq_compositor)
, _started (false)
{
xcam_mem_clear (&_ia_ae_window);
xcam_mem_clear (&_sensor_descriptor);
xcam_mem_clear (&_manual_limits);
xcam_mem_clear (&_input);
_input.num_exposures = 1;
_input.frame_use = _aiq_compositor->get_frame_use();
_input.flash_mode = ia_aiq_flash_mode_off;
_input.operation_mode = ia_aiq_ae_operation_mode_automatic;
_input.metering_mode = ia_aiq_ae_metering_mode_evaluative;
_input.priority_mode = ia_aiq_ae_priority_mode_normal;
_input.flicker_reduction_mode = ia_aiq_ae_flicker_reduction_auto;
_input.sensor_descriptor = NULL;
_input.exposure_window = NULL;
_input.exposure_coordinate = NULL;
_input.ev_shift = 0.0;
_input.manual_exposure_time_us = -1;
_input.manual_analog_gain = -1.0;
_input.manual_iso = -1.0;
_input.aec_features = NULL;
_input.manual_limits = NULL;
}
bool
AiqAeHandler::set_description (struct atomisp_sensor_mode_data *sensor_data)
{
XCAM_ASSERT (sensor_data);
_sensor_descriptor.pixel_clock_freq_mhz = sensor_data->vt_pix_clk_freq_mhz / 1000000.0f;
_sensor_descriptor.pixel_periods_per_line = sensor_data->line_length_pck;
_sensor_descriptor.line_periods_per_field = sensor_data->frame_length_lines;
_sensor_descriptor.line_periods_vertical_blanking = sensor_data->frame_length_lines
- (sensor_data->crop_vertical_end - sensor_data->crop_vertical_start + 1)
/ sensor_data->binning_factor_y;
_sensor_descriptor.fine_integration_time_min = sensor_data->fine_integration_time_def;
_sensor_descriptor.fine_integration_time_max_margin = sensor_data->line_length_pck - sensor_data->fine_integration_time_def;
_sensor_descriptor.coarse_integration_time_min = sensor_data->coarse_integration_time_min;
_sensor_descriptor.coarse_integration_time_max_margin = sensor_data->coarse_integration_time_max_margin;
return true;
}
bool
AiqAeHandler::ensure_ia_parameters ()
{
bool ret = true;
ret = ret && ensure_ae_mode ();
ret = ret && ensure_ae_metering_mode ();
ret = ret && ensure_ae_priority_mode ();
ret = ret && ensure_ae_flicker_mode ();
ret = ret && ensure_ae_manual ();
ret = ret && ensure_ae_ev_shift ();
_input.sensor_descriptor = &_sensor_descriptor;
return ret;
}
bool AiqAeHandler::ensure_ae_mode ()
{
XCamAeMode mode = this->get_mode_unlock();
switch (mode) {
case XCAM_AE_MODE_AUTO:
case XCAM_AE_MODE_MANUAL:
_input.operation_mode = ia_aiq_ae_operation_mode_automatic;
break;
case XCAM_AE_MODE_NOT_SET:
default:
XCAM_LOG_ERROR("unsupported ae mode:%d", mode);
return false;
}
return true;
}
bool AiqAeHandler::ensure_ae_metering_mode ()
{
XCamAeMeteringMode mode = this->get_metering_mode_unlock();
_input.exposure_window = NULL;
switch (mode) {
case XCAM_AE_METERING_MODE_AUTO:
_input.metering_mode = ia_aiq_ae_metering_mode_evaluative;
break;
case XCAM_AE_METERING_MODE_SPOT:
{
_input.metering_mode = ia_aiq_ae_metering_mode_evaluative;
const XCam3AWindow & window = this->get_window_unlock();
if (window.x_end > window.x_start &&
window.y_end > window.y_start) {
_aiq_compositor->convert_window_to_ia(window, _ia_ae_window);
_input.exposure_window = &_ia_ae_window;
}
}
break;
case XCAM_AE_METERING_MODE_CENTER:
_input.metering_mode = ia_aiq_ae_metering_mode_center;
break;
default:
XCAM_LOG_ERROR("unsupported ae mode:%d", mode);
return false;
}
return true;
}
bool AiqAeHandler::ensure_ae_priority_mode ()
{
_input.priority_mode = ia_aiq_ae_priority_mode_normal;
return true;
}
bool AiqAeHandler::ensure_ae_flicker_mode ()
{
XCamFlickerMode mode = this->get_flicker_mode_unlock ();
switch (mode) {
case XCAM_AE_FLICKER_MODE_AUTO:
_input.flicker_reduction_mode = ia_aiq_ae_flicker_reduction_auto;
break;
case XCAM_AE_FLICKER_MODE_50HZ:
_input.flicker_reduction_mode = ia_aiq_ae_flicker_reduction_50hz;
break;
case XCAM_AE_FLICKER_MODE_60HZ:
_input.flicker_reduction_mode = ia_aiq_ae_flicker_reduction_60hz;
break;
case XCAM_AE_FLICKER_MODE_OFF:
_input.flicker_reduction_mode = ia_aiq_ae_flicker_reduction_off;
break;
default:
XCAM_LOG_ERROR ("flicker mode(%d) unknown", mode);
return false;
}
return true;
}
bool AiqAeHandler::ensure_ae_manual ()
{
_input.manual_exposure_time_us = get_manual_exposure_time_unlock ();
_input.manual_analog_gain = get_manual_analog_gain_unlock ();
return true;
}
bool AiqAeHandler::ensure_ae_ev_shift ()
{
_input.ev_shift = this->get_ev_shift_unlock();
return true;
}
SmartPtr<X3aResult>
AiqAeHandler::pop_result ()
{
//AnalyzerHandler::HanlderLock lock(this);
X3aIspExposureResult *result = new X3aIspExposureResult(XCAM_IMAGE_PROCESS_ONCE);
struct atomisp_exposure sensor;
XCam3aResultExposure exposure;
xcam_mem_clear (&sensor);
sensor.integration_time[0] = _result.sensor_exp_param.coarse_integration_time;
sensor.integration_time[1] = _result.sensor_exp_param.fine_integration_time;
sensor.gain[0] = _result.sensor_exp_param.analog_gain_code_global;
sensor.gain[1] = _result.sensor_exp_param.digital_gain_global;
result->set_isp_config (sensor);
xcam_mem_clear (&exposure);
exposure.exposure_time = _result.aiq_exp_param.exposure_time_us;
exposure.analog_gain = _result.aiq_exp_param.analog_gain;
exposure.digital_gain = _result.aiq_exp_param.digital_gain;
exposure.aperture = _result.aiq_exp_param.aperture_fn;
result->set_standard_result (exposure);
return result;
}
XCamReturn
AiqAeHandler::analyze (X3aResultList &output)
{
ia_aiq *ia_handle = NULL;
ia_aiq_ae_results *ae_result = NULL;
ia_aiq_exposure_sensor_parameters *cur_sensor_result = NULL;
ia_err ia_error = ia_err_none;
bool need_apply = false;
SmartPtr<X3aResult> result;
AnalyzerHandler::HanlderLock lock(this);
if (!ensure_ia_parameters ()) {
XCAM_LOG_ERROR ("AIQ AE ensure ia parameters failed");
return XCAM_RETURN_ERROR_PARAM;
}
ia_handle = _aiq_compositor->get_handle ();
XCAM_ASSERT (ia_handle);
ia_error = ia_aiq_ae_run (ia_handle, &_input, &ae_result);
XCAM_FAIL_RETURN (ERROR, ia_error == ia_err_none, XCAM_RETURN_ERROR_AIQ, "AIQ run AE failed");
cur_sensor_result = ae_result->exposures[0].sensor_exposure;
if (!_started) {
_result.copy (ae_result);
_started = true;
need_apply = true;
} else {
//TODO
ia_aiq_exposure_sensor_parameters *last_sensor_res = &_result.sensor_exp_param;
if (last_sensor_res->coarse_integration_time != cur_sensor_result->coarse_integration_time ||
last_sensor_res->fine_integration_time != cur_sensor_result->fine_integration_time ||
last_sensor_res->analog_gain_code_global != cur_sensor_result->analog_gain_code_global ||
last_sensor_res->digital_gain_global != cur_sensor_result->digital_gain_global) {
ia_aiq_exposure_sensor_parameters cur_cp_res = *cur_sensor_result;
if (!manual_control_result (cur_cp_res, *last_sensor_res)) {
XCAM_LOG_WARNING ("manual control AE result failed");
}
_result.copy (ae_result);
_result.sensor_exp_param = cur_cp_res;
need_apply = true;
}
}
if (need_apply) {
result = pop_result ();
if (result.ptr())
output.push_back (result);
}
return XCAM_RETURN_NO_ERROR;
}
bool
AiqAeHandler::manual_control_result (
ia_aiq_exposure_sensor_parameters &cur_res,
const ia_aiq_exposure_sensor_parameters &last_res)
{
adjust_ae_speed (cur_res, last_res, this->get_speed_unlock());
adjust_ae_limitation (cur_res);
return true;
}
void
AiqAeHandler::adjust_ae_speed (
ia_aiq_exposure_sensor_parameters &cur_res,
const ia_aiq_exposure_sensor_parameters &last_res,
double ae_speed)
{
double last_gain, input_gain, ret_gain;
ia_aiq_exposure_sensor_parameters tmp_res;
if (XCAM_DOUBLE_EQUAL_AROUND(ae_speed, 1.0 ))
return;
xcam_mem_clear (&tmp_res);
tmp_res.coarse_integration_time = _calculate_new_value_by_speed (
last_res.coarse_integration_time,
cur_res.coarse_integration_time,
ae_speed);
last_gain = _imx185_sensor_gain_code_to_mutiplier (last_res.analog_gain_code_global);
input_gain = _imx185_sensor_gain_code_to_mutiplier (cur_res.analog_gain_code_global);
ret_gain = _calculate_new_value_by_speed (last_gain, input_gain, ae_speed);
tmp_res.analog_gain_code_global = _mutiplier_to_imx185_sensor_gain_code (ret_gain);
XCAM_LOG_DEBUG ("AE speed: from (shutter:%d, gain:%d[%.03f]) to (shutter:%d, gain:%d[%.03f])",
cur_res.coarse_integration_time, cur_res.analog_gain_code_global, input_gain,
tmp_res.coarse_integration_time, tmp_res.analog_gain_code_global, ret_gain);
cur_res.coarse_integration_time = tmp_res.coarse_integration_time;
cur_res.analog_gain_code_global = tmp_res.analog_gain_code_global;
}
void
AiqAeHandler::adjust_ae_limitation (ia_aiq_exposure_sensor_parameters &cur_res)
{
ia_aiq_exposure_sensor_descriptor * desc = &_sensor_descriptor;
uint64_t exposure_min = 0, exposure_max = 0;
double analog_max = get_max_analog_gain_unlock ();
uint32_t min_coarse_value = 0, max_coarse_value = 0;
get_exposure_time_range_unlock (exposure_min, exposure_max);
if (exposure_min) {
min_coarse_value = _time_to_coarse_line (desc, exposure_min);
if (min_coarse_value < desc->coarse_integration_time_min)
min_coarse_value = desc->coarse_integration_time_min;
if (cur_res.coarse_integration_time < min_coarse_value)
cur_res.coarse_integration_time = min_coarse_value;
}
if (exposure_max) {
max_coarse_value = _time_to_coarse_line (desc, (uint32_t)exposure_max);
if (max_coarse_value > (uint32_t)(desc->line_periods_per_field - desc->coarse_integration_time_max_margin))
max_coarse_value = desc->line_periods_per_field - desc->coarse_integration_time_max_margin;
if (cur_res.coarse_integration_time > max_coarse_value)
cur_res.coarse_integration_time = max_coarse_value;
}
if (analog_max >= 1.0) {
/* limit gains */
double gain = _imx185_sensor_gain_code_to_mutiplier (cur_res.analog_gain_code_global);
if (gain > analog_max)
cur_res.analog_gain_code_global = _mutiplier_to_imx185_sensor_gain_code (analog_max);
}
}
XCamFlickerMode
AiqAeHandler::get_flicker_mode ()
{
{
AnalyzerHandler::HanlderLock lock(this);
}
return AeHandler::get_flicker_mode ();
}
int64_t
AiqAeHandler::get_current_exposure_time ()
{
AnalyzerHandler::HanlderLock lock(this);
return (int64_t)_result.aiq_exp_param.exposure_time_us;
}
double
AiqAeHandler::get_current_analog_gain ()
{
AnalyzerHandler::HanlderLock lock(this);
return (double)_result.aiq_exp_param.analog_gain;
}
double
AiqAeHandler::get_max_analog_gain ()
{
{
AnalyzerHandler::HanlderLock lock(this);
}
return AeHandler::get_max_analog_gain ();
}
AiqAwbHandler::AiqAwbHandler (SmartPtr<AiqCompositor> &aiq_compositor)
: _aiq_compositor (aiq_compositor)
, _started (false)
{
xcam_mem_clear (&_cct_range);
xcam_mem_clear (&_result);
xcam_mem_clear (&_history_result);
xcam_mem_clear (&_cct_range);
xcam_mem_clear (&_input);
_input.frame_use = aiq_compositor->get_frame_use ();
_input.scene_mode = ia_aiq_awb_operation_mode_auto;
_input.manual_cct_range = NULL;
_input.manual_white_coordinate = NULL;
}
XCamReturn
AiqAwbHandler::analyze (X3aResultList &output)
{
ia_aiq *ia_handle = NULL;
ia_aiq_awb_results *awb_ret = NULL;
ia_err ia_error = ia_err_none;
XCAM_UNUSED (output);
AnalyzerHandler::HanlderLock lock(this);
if (!ensure_ia_parameters ()) {
XCAM_LOG_ERROR ("AIQ AE ensure ia parameters failed");
return XCAM_RETURN_ERROR_PARAM;
}
ia_handle = _aiq_compositor->get_handle ();
XCAM_ASSERT (ia_handle);
ia_error = ia_aiq_awb_run (ia_handle, &_input, &awb_ret);
XCAM_FAIL_RETURN (ERROR, ia_error == ia_err_none, XCAM_RETURN_ERROR_AIQ, "AIQ run AWB failed");
_result = *awb_ret;
if (!_started) {
_history_result = _result;
_started = true;
}
adjust_speed (_history_result);
_history_result = _result;
return XCAM_RETURN_NO_ERROR;
}
bool
AiqAwbHandler::ensure_ia_parameters ()
{
bool ret = true;
_input.frame_use = _aiq_compositor->get_frame_use ();
ret = ret && ensure_awb_mode ();
return ret;
}
bool
AiqAwbHandler::ensure_awb_mode ()
{
XCamAwbMode mode = get_mode_unlock();
_input.manual_cct_range = NULL;
_input.scene_mode = ia_aiq_awb_operation_mode_auto;
switch (mode) {
case XCAM_AWB_MODE_AUTO:
_input.scene_mode = ia_aiq_awb_operation_mode_auto;
break;
case XCAM_AWB_MODE_MANUAL: {
uint32_t cct_min = 0, cct_max = 0;
get_cct_range_unlock (cct_min, cct_max);
if (cct_min && cct_max) {
_input.scene_mode = ia_aiq_awb_operation_mode_manual_cct_range;
_cct_range.max_cct = cct_min;
_cct_range.min_cct = cct_max;
_input.manual_cct_range = &_cct_range;
} else
_input.scene_mode = ia_aiq_awb_operation_mode_auto;
break;
}
case XCAM_AWB_MODE_DAYLIGHT:
_input.scene_mode = ia_aiq_awb_operation_mode_daylight;
break;
case XCAM_AWB_MODE_SUNSET:
_input.scene_mode = ia_aiq_awb_operation_mode_sunset;
break;
case XCAM_AWB_MODE_CLOUDY:
_input.scene_mode = ia_aiq_awb_operation_mode_partly_overcast;
break;
case XCAM_AWB_MODE_TUNGSTEN:
_input.scene_mode = ia_aiq_awb_operation_mode_incandescent;
break;
case XCAM_AWB_MODE_FLUORESCENT:
_input.scene_mode = ia_aiq_awb_operation_mode_fluorescent;
break;
case XCAM_AWB_MODE_WARM_FLUORESCENT:
_input.scene_mode = ia_aiq_awb_operation_mode_incandescent;
break;
case XCAM_AWB_MODE_SHADOW:
_input.scene_mode = ia_aiq_awb_operation_mode_fully_overcast;
break;
case XCAM_AWB_MODE_WARM_INCANDESCENT:
_input.scene_mode = ia_aiq_awb_operation_mode_incandescent;
break;
case XCAM_AWB_MODE_NOT_SET:
break;
default:
XCAM_LOG_ERROR ("unknown or unsupported AWB mode(%d)", mode);
return false;
}
return true;
}
void
AiqAwbHandler::adjust_speed (const ia_aiq_awb_results &last_ret)
{
_result.final_r_per_g =
_calculate_new_value_by_speed (
last_ret.final_r_per_g, _result.final_r_per_g, get_speed_unlock ());
_result.final_b_per_g =
_calculate_new_value_by_speed (
last_ret.final_b_per_g, _result.final_b_per_g, get_speed_unlock ());
}
XCamReturn
AiqAfHandler::analyze (X3aResultList &output)
{
// TODO
XCAM_UNUSED (output);
return XCAM_RETURN_NO_ERROR;
}
AiqCommonHandler::AiqCommonHandler (SmartPtr<AiqCompositor> &aiq_compositor)
: _aiq_compositor (aiq_compositor)
, _gbce_result (NULL)
{
}
XCamReturn
AiqCommonHandler::analyze (X3aResultList &output)
{
ia_aiq *ia_handle = NULL;
ia_aiq_gbce_results *gbce_result = NULL;
ia_err ia_error = ia_err_none;
XCAM_UNUSED (output);
AnalyzerHandler::HanlderLock lock(this);
if (has_gbce_unlock()) {
ia_aiq_gbce_input_params gbce_input;
xcam_mem_clear (&gbce_input);
gbce_input.gbce_level = ia_aiq_gbce_level_use_tuning;
gbce_input.frame_use = _aiq_compositor->get_frame_use ();
gbce_input.ev_shift = 0; // Todo
ia_handle = _aiq_compositor->get_handle ();
XCAM_ASSERT (ia_handle);
ia_error = ia_aiq_gbce_run (ia_handle, &gbce_input, &gbce_result);
XCAM_FAIL_RETURN (ERROR, ia_error == ia_err_none, XCAM_RETURN_ERROR_AIQ, "AIQ run GBCE failed");
//TODO, need copy GBCE result out, not just assign
_gbce_result = gbce_result;
} else {
_gbce_result = NULL;
}
return XCAM_RETURN_NO_ERROR;
}
class CmcParser {
public:
explicit CmcParser (ia_binary_data &cpf)
{
_cmc = ia_cmc_parser_init (&cpf);
}
~CmcParser ()
{
if (_cmc)
ia_cmc_parser_deinit (_cmc);
}
ia_cmc_t *get() {
return _cmc;
}
private:
ia_cmc_t *_cmc;
};
void
AiqCompositor::convert_window_to_ia (const XCam3AWindow &window, ia_rectangle &ia_window)
{
ia_rectangle source;
ia_coordinate_system source_system;
ia_coordinate_system target_system = {IA_COORDINATE_TOP, IA_COORDINATE_LEFT, IA_COORDINATE_BOTTOM, IA_COORDINATE_RIGHT};
source_system.left = 0;
source_system.top = 0;
source_system.right = this->_width;
source_system.bottom = this->_height;
XCAM_ASSERT (_width && _height);
source.left = window.x_start;
source.top = window.y_start;
source.right = window.x_end;
source.bottom = window.y_end;
ia_coordinate_convert_rect (&source_system, &source, &target_system, &ia_window);
}
AiqCompositor::AiqCompositor ()
: _ia_handle (NULL)
, _ia_mkn (NULL)
, _pa_result (NULL)
, _frame_use (ia_aiq_frame_use_video)
, _width (0)
, _height (0)
{
xcam_mem_clear (&_frame_params);
}
AiqCompositor::~AiqCompositor ()
{
}
bool
AiqCompositor::open (ia_binary_data &cpf)
{
CmcParser cmc (cpf);
_ia_mkn = ia_mkn_init (ia_mkn_cfg_compression, 32000, 100000);
_ia_handle =
ia_aiq_init (
&cpf, NULL, NULL,
MAX_STATISTICS_WIDTH, MAX_STATISTICS_HEIGHT,
1, //max_num_stats_in
cmc.get(),
_ia_mkn);
if (_ia_handle == NULL) {
XCAM_LOG_WARNING ("AIQ init failed");
return false;
}
_adaptor = new IaIspAdaptor22;
XCAM_ASSERT (_adaptor.ptr());
if (!_adaptor->init (&cpf, MAX_STATISTICS_WIDTH, MAX_STATISTICS_HEIGHT, cmc.get(), _ia_mkn)) {
XCAM_LOG_WARNING ("AIQ isp adaptor init failed");
return false;
}
_pa_result = NULL;
XCAM_LOG_DEBUG ("Aiq compositor opened");
return true;
}
void
AiqCompositor::close ()
{
_adaptor.release ();
if (_ia_handle) {
ia_aiq_deinit (_ia_handle);
_ia_handle = NULL;
}
if (_ia_mkn) {
ia_mkn_uninit (_ia_mkn);
_ia_mkn = NULL;
}
_ae_handler.release ();
_awb_handler.release ();
_af_handler.release ();
_common_handler.release ();
_pa_result = NULL;
XCAM_LOG_DEBUG ("Aiq compositor closed");
}
bool
AiqCompositor::set_sensor_mode_data (struct atomisp_sensor_mode_data *sensor_mode)
{
_frame_params.horizontal_crop_offset = sensor_mode->crop_horizontal_start;
_frame_params.vertical_crop_offset = sensor_mode->crop_vertical_start;
_frame_params.cropped_image_height = sensor_mode->crop_vertical_end - sensor_mode->crop_vertical_start + 1;
_frame_params.cropped_image_width = sensor_mode->crop_horizontal_end - sensor_mode->crop_horizontal_start + 1;
/* hard code to 254? */
_frame_params.horizontal_scaling_denominator = 254;
_frame_params.vertical_scaling_denominator = 254;
if ((_frame_params.cropped_image_width == 0) || (_frame_params.cropped_image_height == 0)) {
_frame_params.horizontal_scaling_numerator = 0;
_frame_params.vertical_scaling_numerator = 0;
} else {
_frame_params.horizontal_scaling_numerator =
sensor_mode->output_width * 254 * sensor_mode->binning_factor_x / _frame_params.cropped_image_width;
_frame_params.vertical_scaling_numerator =
sensor_mode->output_height * 254 * sensor_mode->binning_factor_y / _frame_params.cropped_image_height;
}
if (!_ae_handler->set_description (sensor_mode)) {
XCAM_LOG_WARNING ("AIQ set ae description failed");
return XCAM_RETURN_ERROR_AIQ;
}
return true;
}
bool
AiqCompositor::set_3a_stats (SmartPtr<X3aIspStatistics> &stats)
{
ia_aiq_statistics_input_params aiq_stats_input;
ia_aiq_rgbs_grid *rgbs_grids = NULL;
ia_aiq_af_grid *af_grids = NULL;
xcam_mem_clear (&aiq_stats_input);
aiq_stats_input.frame_timestamp = stats->get_timestamp();
aiq_stats_input.frame_id = stats->get_timestamp() + 1;
aiq_stats_input.rgbs_grids = (const ia_aiq_rgbs_grid **)&rgbs_grids;
aiq_stats_input.num_rgbs_grids = 1;
aiq_stats_input.af_grids = (const ia_aiq_af_grid **)(&af_grids);
aiq_stats_input.num_af_grids = 1;
aiq_stats_input.frame_af_parameters = NULL;
aiq_stats_input.external_histograms = NULL;
aiq_stats_input.num_external_histograms = 0;
aiq_stats_input.camera_orientation = ia_aiq_camera_orientation_unknown;
if (_pa_result)
aiq_stats_input.frame_pa_parameters = _pa_result;
if (_ae_handler->is_started())
aiq_stats_input.frame_ae_parameters = _ae_handler->get_result ();
//if (_awb_handler->is_started())
// aiq_stats_input.frame_awb_parameters = _awb_handler->get_result();
if (!_adaptor->convert_statistics (stats->get_3a_stats(), &rgbs_grids, &af_grids)) {
XCAM_LOG_WARNING ("ia isp adaptor convert 3a stats failed");
return false;
}
XCAM_LOG_DEBUG ("statistics grid info, width:%u, height:%u, blk_r:%u, blk_b:%u, blk_gr:%u, blk_gb:%u",
aiq_stats_input.rgbs_grids[0]->grid_width,
aiq_stats_input.rgbs_grids[0]->grid_height,
aiq_stats_input.rgbs_grids[0]->blocks_ptr->avg_r,
aiq_stats_input.rgbs_grids[0]->blocks_ptr->avg_b,
aiq_stats_input.rgbs_grids[0]->blocks_ptr->avg_gr,
aiq_stats_input.rgbs_grids[0]->blocks_ptr->avg_gb);
if (ia_aiq_statistics_set(get_handle (), &aiq_stats_input) != ia_err_none) {
XCAM_LOG_ERROR ("Aiq set statistic failed");
return false;
}
return true;
}
XCamReturn AiqCompositor::integrate (X3aResultList &results)
{
IspInputParameters isp_params;
ia_aiq_pa_input_params pa_input;
ia_aiq_pa_results *pa_result = NULL;
ia_err ia_error = ia_err_none;
ia_binary_data output;
AiqAeHandler *aiq_ae = _ae_handler.ptr();
AiqAwbHandler *aiq_awb = _awb_handler.ptr();
AiqAfHandler *aiq_af = _af_handler.ptr();
AiqCommonHandler *aiq_common = _common_handler.ptr();
struct atomisp_parameters *isp_3a_result = NULL;
SmartPtr<X3aResult> isp_results;
XCAM_FAIL_RETURN (
ERROR,
aiq_ae && aiq_awb && aiq_af && aiq_common,
XCAM_RETURN_ERROR_PARAM,
"handlers are not AIQ inherited");
xcam_mem_clear (&pa_input);
pa_input.frame_use = _frame_use;
pa_input.awb_results = aiq_awb->get_result ();
if (aiq_ae->is_started())
pa_input.exposure_params = (aiq_ae->get_result ())->exposures[0].exposure;
pa_input.sensor_frame_params = &_frame_params;
pa_input.color_gains = NULL;
ia_error = ia_aiq_pa_run (_ia_handle, &pa_input, &pa_result);
if (ia_error != ia_err_none) {
XCAM_LOG_WARNING ("AIQ pa run failed"); // but not return error
}
_pa_result = pa_result;
isp_params.frame_use = _frame_use;
isp_params.awb_results = aiq_awb->get_result ();
if (aiq_ae->is_started())
isp_params.exposure_results = (aiq_ae->get_result ())->exposures[0].exposure;
isp_params.gbce_results = aiq_common->get_gbce_result ();
isp_params.sensor_frame_params = &_frame_params;
isp_params.pa_results = pa_result;
isp_params.manual_brightness = (int8_t)(aiq_common->get_brightness_unlock() * 128.0);
isp_params.manual_contrast = (int8_t)(aiq_common->get_contrast_unlock() * 128.0);
isp_params.manual_saturation = (int8_t)(aiq_common->get_saturation_unlock() * 128.0);
isp_params.manual_hue = (int8_t)(aiq_common->get_hue_unlock() * 128.0);
isp_params.manual_sharpness = (int8_t)(aiq_common->get_sharpness_unlock() * 128.0);
isp_params.manual_nr_level = (int8_t)(aiq_common->get_nr_level_unlock() * 128.0);
xcam_mem_clear (&output);
if (!_adaptor->run (&isp_params, &output)) {
XCAM_LOG_ERROR("Aiq to isp adaptor running failed");
return XCAM_RETURN_ERROR_ISP;
}
isp_3a_result = ((struct atomisp_parameters *)output.data);
isp_results = generate_3a_configs (isp_3a_result);
results.push_back (isp_results);
return XCAM_RETURN_NO_ERROR;
}
SmartPtr<X3aResult>
AiqCompositor::generate_3a_configs (struct atomisp_parameters *parameters)
{
SmartPtr<X3aResult> ret;
X3aAtomIspParametersResult *x3a_result =
new X3aAtomIspParametersResult (XCAM_IMAGE_PROCESS_ONCE);
x3a_result->set_isp_config (*parameters);
ret = x3a_result;
return ret;
}
void
AiqCompositor::set_ae_handler (SmartPtr<AiqAeHandler> &handler)
{
XCAM_ASSERT (!_ae_handler.ptr());
_ae_handler = handler;
}
void
AiqCompositor::set_awb_handler (SmartPtr<AiqAwbHandler> &handler)
{
XCAM_ASSERT (!_awb_handler.ptr());
_awb_handler = handler;
}
void
AiqCompositor::set_af_handler (SmartPtr<AiqAfHandler> &handler)
{
XCAM_ASSERT (!_af_handler.ptr());
_af_handler = handler;
}
void
AiqCompositor::set_common_handler (SmartPtr<AiqCommonHandler> &handler)
{
XCAM_ASSERT (!_common_handler.ptr());
_common_handler = handler;
}
};