/*
* aiq_wrapper.cpp - aiq wrapper:
*
* 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 <base/xcam_3a_description.h>
#include <xcam_std.h>
#include "x3a_analyzer_aiq.h"
#include "x3a_statistics_queue.h"
#include "aiq3a_utils.h"
#include "x3a_result_factory.h"
#include "x3a_analyze_tuner.h"
#define DEFAULT_AIQ_CPF_FILE "/etc/atomisp/imx185.cpf"
using namespace XCam;
#define AIQ_CONTEXT_CAST(context) ((XCam3AAiqContext*)(context))
class XCam3AAiqContext
: public AnalyzerCallback
{
public:
XCam3AAiqContext ();
~XCam3AAiqContext ();
bool setup_analyzer (struct atomisp_sensor_mode_data &sensor_mode_data, const char *cpf);
void set_size (uint32_t width, uint32_t height);
bool setup_stats_pool (uint32_t bit_depth = 8);
bool is_stats_pool_ready () const {
return (_stats_pool.ptr () ? true : false);
}
SmartPtr<X3aAnalyzeTuner> &get_analyzer () {
return _analyzer;
}
SmartPtr<X3aIspStatistics> get_stats_buffer ();
uint32_t get_results (X3aResultList &results);
// derive from AnalyzerCallback
virtual void x3a_calculation_done (XAnalyzer *analyzer, X3aResultList &results);
void update_brightness_result(XCamCommonParam *params);
private:
XCAM_DEAD_COPY (XCam3AAiqContext);
private:
// members
SmartPtr<X3aAnalyzeTuner> _analyzer;
SmartPtr<X3aStatisticsQueue> _stats_pool;
uint32_t _video_width;
uint32_t _video_height;
Mutex _result_mutex;
X3aResultList _results;
double _brightness_level;
};
XCam3AAiqContext::XCam3AAiqContext ()
: _video_width (0)
, _video_height (0)
, _brightness_level(0)
{
}
XCam3AAiqContext::~XCam3AAiqContext ()
{
_analyzer->stop ();
_analyzer->deinit ();
}
bool
XCam3AAiqContext::setup_analyzer (struct atomisp_sensor_mode_data &sensor_mode_data, const char *cpf)
{
XCAM_ASSERT (!_analyzer.ptr ());
SmartPtr<X3aAnalyzer> aiq_analyzer = new X3aAnalyzerAiq (sensor_mode_data, cpf);
XCAM_ASSERT (aiq_analyzer.ptr ());
_analyzer = new X3aAnalyzeTuner ();
XCAM_ASSERT (_analyzer.ptr ());
_analyzer->set_analyzer (aiq_analyzer);
_analyzer->set_results_callback (this);
return true;
}
void
XCam3AAiqContext::set_size (uint32_t width, uint32_t height)
{
_video_width = width;
_video_height = height;
}
bool
XCam3AAiqContext::setup_stats_pool (uint32_t bit_depth)
{
VideoBufferInfo info;
info.init (XCAM_PIX_FMT_SGRBG16, _video_width, _video_height);
_stats_pool = new X3aStatisticsQueue;
XCAM_ASSERT (_stats_pool.ptr ());
_stats_pool->set_bit_depth (bit_depth);
XCAM_FAIL_RETURN (
WARNING,
_stats_pool->set_video_info (info),
false,
"3a stats set video info failed");
if (!_stats_pool->reserve (6)) {
XCAM_LOG_WARNING ("init_3a_stats_pool failed to reserve stats buffer.");
return false;
}
return true;
}
SmartPtr<X3aIspStatistics>
XCam3AAiqContext::get_stats_buffer ()
{
SmartPtr<X3aIspStatistics> new_stats =
_stats_pool->get_buffer (_stats_pool).dynamic_cast_ptr<X3aIspStatistics> ();
XCAM_FAIL_RETURN (
WARNING,
new_stats.ptr (),
NULL,
"get isp stats buffer failed");
return new_stats;
}
void
XCam3AAiqContext::x3a_calculation_done (XAnalyzer *analyzer, X3aResultList &results)
{
XCAM_UNUSED (analyzer);
SmartLock locker (_result_mutex);
_results.insert (_results.end (), results.begin (), results.end ());
}
void
XCam3AAiqContext::update_brightness_result(XCamCommonParam *params)
{
if( params->brightness == _brightness_level)
return;
_brightness_level = params->brightness;
XCam3aResultBrightness xcam3a_brightness_result;
xcam_mem_clear (xcam3a_brightness_result);
xcam3a_brightness_result.head.type = XCAM_3A_RESULT_BRIGHTNESS;
xcam3a_brightness_result.head.process_type = XCAM_IMAGE_PROCESS_ALWAYS;
xcam3a_brightness_result.head.version = XCAM_VERSION;
xcam3a_brightness_result.brightness_level = _brightness_level;
SmartPtr<X3aResult> brightness_result =
X3aResultFactory::instance ()->create_3a_result ((XCam3aResultHead*)&xcam3a_brightness_result);
_results.push_back(brightness_result);
}
uint32_t
XCam3AAiqContext::get_results (X3aResultList &results)
{
uint32_t size = 0;
SmartLock locker (_result_mutex);
results.assign (_results.begin (), _results.end ());
size = _results.size ();
_results.clear ();
return size;
}
static SmartPtr<X3aAnalyzeTuner>
get_analyzer (XCam3AContext *context)
{
XCam3AAiqContext *aiq_context = AIQ_CONTEXT_CAST (context);
if (!aiq_context)
return NULL;
return aiq_context->get_analyzer ();
}
static XCamReturn
xcam_create_context (XCam3AContext **context)
{
XCAM_ASSERT (context);
XCam3AAiqContext *aiq_context = new XCam3AAiqContext ();
*context = ((XCam3AContext*)(aiq_context));
return XCAM_RETURN_NO_ERROR;
}
static XCamReturn
xcam_destroy_context (XCam3AContext *context)
{
XCam3AAiqContext *aiq_context = AIQ_CONTEXT_CAST (context);
delete aiq_context;
return XCAM_RETURN_NO_ERROR;
}
static XCamReturn
xcam_configure_3a (XCam3AContext *context, uint32_t width, uint32_t height, double framerate)
{
XCam3AAiqContext *aiq_context = AIQ_CONTEXT_CAST (context);
XCamReturn ret = XCAM_RETURN_NO_ERROR;
struct atomisp_sensor_mode_data sensor_mode_data;
switch ((int)framerate) {
case 30:
sensor_mode_data.coarse_integration_time_min = 1;
sensor_mode_data.coarse_integration_time_max_margin = 1;
sensor_mode_data.fine_integration_time_min = 0;
sensor_mode_data.fine_integration_time_max_margin = 0;
sensor_mode_data.fine_integration_time_def = 0;
sensor_mode_data.frame_length_lines = 1125;
sensor_mode_data.line_length_pck = 1100;
sensor_mode_data.read_mode = 0;
sensor_mode_data.vt_pix_clk_freq_mhz = 37125000;
sensor_mode_data.crop_horizontal_start = 0;
sensor_mode_data.crop_vertical_start = 0;
sensor_mode_data.crop_horizontal_end = 1920;
sensor_mode_data.crop_vertical_end = 1080;
sensor_mode_data.output_width = 1920;
sensor_mode_data.output_height = 1080;
sensor_mode_data.binning_factor_x = 1;
sensor_mode_data.binning_factor_y = 1;
break;
default:
sensor_mode_data.coarse_integration_time_min = 1;
sensor_mode_data.coarse_integration_time_max_margin = 1;
sensor_mode_data.fine_integration_time_min = 0;
sensor_mode_data.fine_integration_time_max_margin = 0;
sensor_mode_data.fine_integration_time_def = 0;
sensor_mode_data.frame_length_lines = 1125;
sensor_mode_data.line_length_pck = 1320;
sensor_mode_data.read_mode = 0;
sensor_mode_data.vt_pix_clk_freq_mhz = 37125000;
sensor_mode_data.crop_horizontal_start = 0;
sensor_mode_data.crop_vertical_start = 0;
sensor_mode_data.crop_horizontal_end = 1920;
sensor_mode_data.crop_vertical_end = 1080;
sensor_mode_data.output_width = 1920;
sensor_mode_data.output_height = 1080;
sensor_mode_data.binning_factor_x = 1;
sensor_mode_data.binning_factor_y = 1;
break;
}
XCAM_ASSERT (aiq_context);
const char *path_cpf = getenv ("AIQ_CPF_PATH");
XCAM_FAIL_RETURN (
WARNING,
aiq_context->setup_analyzer (sensor_mode_data, path_cpf == NULL ? DEFAULT_AIQ_CPF_FILE : path_cpf),
XCAM_RETURN_ERROR_UNKNOWN,
"setup aiq 3a analyzer failed");
SmartPtr<X3aAnalyzeTuner> analyzer = aiq_context->get_analyzer ();
ret = analyzer->prepare_handlers ();
XCAM_FAIL_RETURN (
WARNING,
ret == XCAM_RETURN_NO_ERROR,
ret,
"analyzer(aiq3alib) prepare handlers failed");
ret = analyzer->init (width, height, framerate);
XCAM_FAIL_RETURN (
WARNING,
ret == XCAM_RETURN_NO_ERROR,
ret,
"configure aiq 3a failed");
ret = analyzer->start ();
XCAM_FAIL_RETURN (
WARNING,
ret == XCAM_RETURN_NO_ERROR,
ret,
"start aiq 3a failed");
aiq_context->set_size (width, height);
return XCAM_RETURN_NO_ERROR;
}
static XCamReturn
xcam_set_3a_stats (XCam3AContext *context, XCam3AStats *stats, int64_t timestamp)
{
XCamReturn ret = XCAM_RETURN_NO_ERROR;
XCam3AAiqContext *aiq_context = AIQ_CONTEXT_CAST (context);
XCAM_ASSERT (aiq_context);
SmartPtr<X3aAnalyzeTuner> analyzer = aiq_context->get_analyzer ();
XCAM_ASSERT (analyzer.ptr ());
XCAM_ASSERT (stats);
if (!aiq_context->is_stats_pool_ready ()) {
// init statistics queue
XCAM_FAIL_RETURN (
WARNING,
aiq_context->setup_stats_pool (stats->info.bit_depth),
XCAM_RETURN_ERROR_UNKNOWN,
"aiq configure 3a failed on stats pool setup");
}
// Convert stats to atomisp_3a_stats;
SmartPtr<X3aIspStatistics> isp_stats = aiq_context->get_stats_buffer ();
if (!isp_stats.ptr ()) {
XCAM_LOG_WARNING ("get stats bufffer failed or stopped");
return XCAM_RETURN_ERROR_MEM;
}
struct atomisp_3a_statistics *raw_stats = isp_stats->get_isp_stats ();
XCAM_ASSERT (raw_stats);
translate_3a_stats (stats, raw_stats);
isp_stats->set_timestamp (timestamp);
ret = analyzer->push_3a_stats (isp_stats);
if (ret != XCAM_RETURN_NO_ERROR) {
XCAM_LOG_WARNING ("set 3a stats failed");
}
return ret;
}
static XCamReturn
xcam_update_common_params (XCam3AContext *context, XCamCommonParam *params)
{
if (params) {
SmartPtr<X3aAnalyzeTuner> analyzer = get_analyzer (context);
XCAM_ASSERT (analyzer.ptr ());
analyzer->update_common_parameters (*params);
}
#if 0
XCam3AAiqContext *aiq_context = AIQ_CONTEXT_CAST (context);
aiq_context->update_brightness_result(params);
#endif
return XCAM_RETURN_NO_ERROR;
}
static XCamReturn
xcam_analyze_awb (XCam3AContext *context, XCamAwbParam *params)
{
if (params) {
SmartPtr<X3aAnalyzeTuner> analyzer = get_analyzer (context);
XCAM_ASSERT (analyzer.ptr ());
analyzer->update_awb_parameters (*params);
}
return XCAM_RETURN_NO_ERROR;
}
static XCamReturn
xcam_analyze_ae (XCam3AContext *context, XCamAeParam *params)
{
if (params) {
SmartPtr<X3aAnalyzeTuner> analyzer = get_analyzer (context);
XCAM_ASSERT (analyzer.ptr ());
analyzer->update_ae_parameters (*params);
}
return XCAM_RETURN_NO_ERROR;
}
static XCamReturn
xcam_analyze_af (XCam3AContext *context, XCamAfParam *params)
{
if (params) {
SmartPtr<X3aAnalyzeTuner> analyzer = get_analyzer (context);
XCAM_ASSERT (analyzer.ptr ());
analyzer->update_af_parameters (*params);
}
return XCAM_RETURN_NO_ERROR;
}
static XCamReturn
xcam_combine_analyze_results (XCam3AContext *context, XCam3aResultHead *results[], uint32_t *res_count)
{
XCam3AAiqContext *aiq_context = AIQ_CONTEXT_CAST (context);
XCAM_ASSERT (aiq_context);
X3aResultList aiq_results;
uint32_t result_count = aiq_context->get_results (aiq_results);
if (!result_count) {
*res_count = 0;
XCAM_LOG_DEBUG ("aiq wrapper combine with no result out");
return XCAM_RETURN_NO_ERROR;
}
// mark as static
static XCam3aResultHead *res_array[XCAM_3A_MAX_RESULT_COUNT];
xcam_mem_clear (res_array);
XCAM_ASSERT (result_count < XCAM_3A_MAX_RESULT_COUNT);
// result_count may changed
result_count = translate_3a_results_to_xcam (aiq_results, res_array, XCAM_3A_MAX_RESULT_COUNT);
for (uint32_t i = 0; i < result_count; ++i) {
results[i] = res_array[i];
}
*res_count = result_count;
XCAM_ASSERT (result_count > 0);
return XCAM_RETURN_NO_ERROR;
}
static void
xcam_free_results (XCam3aResultHead *results[], uint32_t res_count)
{
for (uint32_t i = 0; i < res_count; ++i) {
if (results[i])
free_3a_result (results[i]);
}
}
XCAM_BEGIN_DECLARE
XCam3ADescription xcam_3a_desciption = {
XCAM_VERSION,
sizeof (XCam3ADescription),
xcam_create_context,
xcam_destroy_context,
xcam_configure_3a,
xcam_set_3a_stats,
xcam_update_common_params,
xcam_analyze_awb,
xcam_analyze_ae,
xcam_analyze_af,
xcam_combine_analyze_results,
xcam_free_results
};
XCAM_END_DECLARE