/* * cl_3a_image_processor.cpp - CL 3A image processor * * 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 */ #include "cl_3a_image_processor.h" #include "cl_context.h" #include "cl_csc_handler.h" #include "cl_bayer_pipe_handler.h" #include "cl_yuv_pipe_handler.h" #if ENABLE_YEENR_HANDLER #include "cl_ee_handler.h" #endif #include "cl_tnr_handler.h" #include "cl_tonemapping_handler.h" #include "cl_newtonemapping_handler.h" #include "cl_bayer_basic_handler.h" #define XCAM_CL_3A_IMAGE_MAX_POOL_SIZE 6 namespace XCam { CL3aImageProcessor::CL3aImageProcessor () : CLImageProcessor ("CL3aImageProcessor") , _output_fourcc (V4L2_PIX_FMT_NV12) , _3a_stats_bits (8) , _pipeline_profile (BasicPipelineProfile) , _capture_stage (TonemappingStage) , _wdr_mode (WDRdisabled) , _tnr_mode (0) , _enable_gamma (true) , _enable_macc (true) , _snr_mode (0) { keep_attached_buf (true); XCAM_LOG_DEBUG ("CL3aImageProcessor constructed"); } CL3aImageProcessor::~CL3aImageProcessor () { XCAM_LOG_DEBUG ("CL3aImageProcessor destructed"); } void CL3aImageProcessor::set_stats_callback (const SmartPtr &callback) { XCAM_ASSERT (callback.ptr ()); _stats_callback = callback; } bool CL3aImageProcessor::set_output_format (uint32_t fourcc) { XCAM_FAIL_RETURN ( WARNING, V4L2_PIX_FMT_NV12 == fourcc, false, "cl 3a processor doesn't support output format: %s", xcam_fourcc_to_string (fourcc)); _output_fourcc = fourcc; return true; } bool CL3aImageProcessor::set_capture_stage (CaptureStage capture_stage) { _capture_stage = capture_stage; return true; } bool CL3aImageProcessor::set_3a_stats_bits (uint32_t bits) { switch (bits) { case 8: case 12: _3a_stats_bits = bits; break; default: XCAM_LOG_WARNING ("cl image processor 3a stats doesn't support %d-bits", bits); return false; } return true; } bool CL3aImageProcessor::can_process_result (SmartPtr &result) { if (result.ptr() == NULL) return false; switch (result->get_type ()) { case XCAM_3A_RESULT_WHITE_BALANCE: case XCAM_3A_RESULT_BLACK_LEVEL: case XCAM_3A_RESULT_R_GAMMA: case XCAM_3A_RESULT_G_GAMMA: case XCAM_3A_RESULT_B_GAMMA: case XCAM_3A_RESULT_RGB2YUV_MATRIX: case XCAM_3A_RESULT_DEFECT_PIXEL_CORRECTION: case XCAM_3A_RESULT_MACC: case XCAM_3A_RESULT_BAYER_NOISE_REDUCTION: case XCAM_3A_RESULT_BRIGHTNESS: case XCAM_3A_RESULT_3D_NOISE_REDUCTION: case XCAM_3A_RESULT_TEMPORAL_NOISE_REDUCTION_YUV: case XCAM_3A_RESULT_EDGE_ENHANCEMENT: return true; default: return false; } return false; } XCamReturn CL3aImageProcessor::apply_3a_results (X3aResultList &results) { XCamReturn ret = XCAM_RETURN_NO_ERROR; for (X3aResultList::iterator iter = results.begin (); iter != results.end (); ++iter) { SmartPtr &result = *iter; ret = apply_3a_result (result); if (ret != XCAM_RETURN_NO_ERROR) break; } return ret; } XCamReturn CL3aImageProcessor::apply_3a_result (SmartPtr &result) { STREAM_LOCK; if (result.ptr() == NULL) return XCAM_RETURN_BYPASS; uint32_t res_type = result->get_type (); switch (res_type) { case XCAM_3A_RESULT_WHITE_BALANCE: { SmartPtr wb_res = result.dynamic_cast_ptr (); XCAM_ASSERT (wb_res.ptr ()); if (_bayer_basic_pipe.ptr ()) { _bayer_basic_pipe->set_wb_config (wb_res->get_standard_result ()); _bayer_basic_pipe->set_3a_result (result); } break; } case XCAM_3A_RESULT_BLACK_LEVEL: { SmartPtr bl_res = result.dynamic_cast_ptr (); XCAM_ASSERT (bl_res.ptr ()); if (_bayer_basic_pipe.ptr ()) { _bayer_basic_pipe->set_blc_config (bl_res->get_standard_result ()); _bayer_basic_pipe->set_3a_result (result); } break; } case XCAM_3A_RESULT_DEFECT_PIXEL_CORRECTION: { SmartPtr def_res = result.dynamic_cast_ptr (); XCAM_ASSERT (def_res.ptr ()); XCAM_UNUSED (def_res); break; } case XCAM_3A_RESULT_RGB2YUV_MATRIX: { SmartPtr csc_res = result.dynamic_cast_ptr (); XCAM_ASSERT (csc_res.ptr ()); if (_csc.ptr()) { _csc->set_matrix (csc_res->get_standard_result ()); _csc->set_3a_result (result); } if (_yuv_pipe.ptr()) { _yuv_pipe->set_rgbtoyuv_matrix (csc_res->get_standard_result ()); _yuv_pipe->set_3a_result (result); } break; } case XCAM_3A_RESULT_MACC: { SmartPtr macc_res = result.dynamic_cast_ptr (); XCAM_ASSERT (macc_res.ptr ()); if (_yuv_pipe.ptr()) { _yuv_pipe->set_macc_table (macc_res->get_standard_result ()); _yuv_pipe->set_3a_result (result); } break; } case XCAM_3A_RESULT_R_GAMMA: case XCAM_3A_RESULT_B_GAMMA: break; case XCAM_3A_RESULT_G_GAMMA: case XCAM_3A_RESULT_Y_GAMMA: { SmartPtr gamma_res = result.dynamic_cast_ptr (); XCAM_ASSERT (gamma_res.ptr ()); if (_bayer_basic_pipe.ptr ()) { _bayer_basic_pipe->set_gamma_table (gamma_res->get_standard_result ()); _bayer_basic_pipe->set_3a_result (result); } break; } case XCAM_3A_RESULT_3D_NOISE_REDUCTION: { SmartPtr nr_res = result.dynamic_cast_ptr (); XCAM_ASSERT (nr_res.ptr ()); XCAM_UNUSED (nr_res); break; } case XCAM_3A_RESULT_TEMPORAL_NOISE_REDUCTION_YUV: { SmartPtr tnr_res = result.dynamic_cast_ptr (); XCAM_ASSERT (tnr_res.ptr ()); if (_yuv_pipe.ptr ()) { _yuv_pipe->set_tnr_yuv_config(tnr_res->get_standard_result ()); _yuv_pipe->set_3a_result (result); } break; } case XCAM_3A_RESULT_EDGE_ENHANCEMENT: { SmartPtr ee_ee_res = result.dynamic_cast_ptr (); XCAM_ASSERT (ee_ee_res.ptr ()); if (_bayer_pipe.ptr()) { _bayer_pipe->set_ee_config (ee_ee_res->get_standard_result ()); _bayer_pipe->set_3a_result (result); } #if ENABLE_YEENR_HANDLER if (_ee.ptr()) { _ee->set_ee_config_ee (ee_ee_res->get_standard_result ()); _ee->set_3a_result (result); } #endif break; } case XCAM_3A_RESULT_BAYER_NOISE_REDUCTION: { SmartPtr bnr_res = result.dynamic_cast_ptr (); XCAM_ASSERT (bnr_res.ptr ()); if (_bayer_pipe.ptr()) { _bayer_pipe->set_bnr_config (bnr_res->get_standard_result ()); _bayer_pipe->set_3a_result (result); } break; } case XCAM_3A_RESULT_BRIGHTNESS: { SmartPtr brightness_res = result.dynamic_cast_ptr (); XCAM_ASSERT (brightness_res.ptr ()); float brightness_level = ((XCam3aResultBrightness)brightness_res->get_standard_result()).brightness_level; XCAM_UNUSED (brightness_level); break; } default: XCAM_LOG_WARNING ("CL3aImageProcessor unknown 3a result:%d", res_type); break; } return XCAM_RETURN_NO_ERROR; } XCamReturn CL3aImageProcessor::create_handlers () { SmartPtr image_handler; SmartPtr context = get_cl_context (); XCAM_ASSERT (context.ptr ()); /* bayer pipeline */ image_handler = create_cl_bayer_basic_image_handler (context, _enable_gamma, _3a_stats_bits); _bayer_basic_pipe = image_handler.dynamic_cast_ptr (); XCAM_FAIL_RETURN ( WARNING, _bayer_basic_pipe.ptr (), XCAM_RETURN_ERROR_CL, "CL3aImageProcessor create bayer basic pipe handler failed"); image_handler->set_pool_size (XCAM_CL_3A_IMAGE_MAX_POOL_SIZE); _bayer_basic_pipe->set_stats_callback (_stats_callback); add_handler (image_handler); /* tone mapping */ switch(_wdr_mode) { case Gaussian: { image_handler = create_cl_tonemapping_image_handler (context); _tonemapping = image_handler.dynamic_cast_ptr (); XCAM_FAIL_RETURN ( WARNING, _tonemapping.ptr (), XCAM_RETURN_ERROR_CL, "CL3aImageProcessor create tonemapping handler failed"); _tonemapping->enable_handler (true); image_handler->set_pool_size (XCAM_CL_3A_IMAGE_MAX_POOL_SIZE); add_handler (image_handler); break; } case Haleq: { image_handler = create_cl_newtonemapping_image_handler (context); _newtonemapping = image_handler.dynamic_cast_ptr (); XCAM_FAIL_RETURN ( WARNING, _newtonemapping.ptr (), XCAM_RETURN_ERROR_CL, "CL3aImageProcessor create tonemapping handler failed"); _newtonemapping->enable_handler (true); image_handler->set_pool_size (XCAM_CL_3A_IMAGE_MAX_POOL_SIZE); add_handler (image_handler); break; } default: XCAM_LOG_DEBUG ("WDR disabled"); break; } /* bayer pipe */ image_handler = create_cl_bayer_pipe_image_handler (context); _bayer_pipe = image_handler.dynamic_cast_ptr (); XCAM_FAIL_RETURN ( WARNING, image_handler.ptr (), XCAM_RETURN_ERROR_CL, "CL3aImageProcessor create bayer pipe handler failed"); _bayer_pipe->enable_denoise (XCAM_DENOISE_TYPE_BNR & _snr_mode); image_handler->set_pool_size (XCAM_CL_3A_IMAGE_MAX_POOL_SIZE * 2); add_handler (image_handler); if(_capture_stage == BasicbayerStage) return XCAM_RETURN_NO_ERROR; image_handler = create_cl_yuv_pipe_image_handler (context); _yuv_pipe = image_handler.dynamic_cast_ptr (); XCAM_FAIL_RETURN ( WARNING, _yuv_pipe.ptr (), XCAM_RETURN_ERROR_CL, "CL3aImageProcessor create yuv pipe handler failed"); _yuv_pipe->set_tnr_enable (_tnr_mode & CL_TNR_TYPE_YUV); image_handler->set_pool_size (XCAM_CL_3A_IMAGE_MAX_POOL_SIZE * 2); add_handler (image_handler); #if ENABLE_YEENR_HANDLER /* ee */ image_handler = create_cl_ee_image_handler (context); _ee = image_handler.dynamic_cast_ptr (); XCAM_FAIL_RETURN ( WARNING, _ee.ptr (), XCAM_RETURN_ERROR_CL, "CL3aImageProcessor create ee handler failed"); _ee->enable_handler (XCAM_DENOISE_TYPE_EE & _snr_mode); image_handler->set_pool_type (CLImageHandler::CLVideoPoolType); image_handler->set_pool_size (XCAM_CL_3A_IMAGE_MAX_POOL_SIZE); add_handler (image_handler); #endif XCAM_FAIL_RETURN ( WARNING, post_config (), XCAM_RETURN_ERROR_CL, "CL3aImageProcessor post_config failed"); return XCAM_RETURN_NO_ERROR; } bool CL3aImageProcessor::post_config () { CLImageProcessor::ImageHandlerList::iterator i_handler = handlers_begin (); CLImageProcessor::ImageHandlerList::iterator end = handlers_end (); uint32_t swap_y_count = 0; bool start_count = false; bool ret = true; if (!_yuv_pipe.ptr ()) //not necessary to check return true; for (; i_handler != end; ++i_handler) { if (!start_count) { SmartPtr convert_yuv = (*i_handler).dynamic_cast_ptr (); if (convert_yuv.ptr () && convert_yuv.ptr () == _yuv_pipe.ptr ()) start_count = true; continue; } SmartPtr clone_y = (*i_handler).dynamic_cast_ptr (); if (clone_y.ptr () && clone_y->is_handler_enabled () && (clone_y->get_clone_flags () & SwappedBuffer::SwapY)) swap_y_count++; } if (swap_y_count % 2 == 1) ret = _yuv_pipe->enable_buf_pool_swap_flags (SwappedBuffer::SwapY | SwappedBuffer::SwapUV, SwappedBuffer::OrderY1Y0 | SwappedBuffer::OrderUV0UV1); else ret = _yuv_pipe->enable_buf_pool_swap_flags (SwappedBuffer::SwapY | SwappedBuffer::SwapUV, SwappedBuffer::OrderY0Y1 | SwappedBuffer::OrderUV0UV1); return ret; } bool CL3aImageProcessor::set_profile (const CL3aImageProcessor::PipelineProfile value) { _pipeline_profile = value; if (value >= AdvancedPipelineProfile) _tnr_mode |= CL_TNR_TYPE_YUV; if (value >= ExtremePipelineProfile) { _snr_mode |= XCAM_DENOISE_TYPE_BNR; } STREAM_LOCK; if (_yuv_pipe.ptr ()) _yuv_pipe->set_tnr_enable (_tnr_mode & CL_TNR_TYPE_YUV); return true; } bool CL3aImageProcessor::set_gamma (bool enable) { _enable_gamma = enable; STREAM_LOCK; return true; } bool CL3aImageProcessor::set_denoise (uint32_t mode) { _snr_mode = mode; STREAM_LOCK; if (_bayer_pipe.ptr ()) _bayer_pipe->enable_denoise (XCAM_DENOISE_TYPE_BNR & _snr_mode); return true; } bool CL3aImageProcessor::set_macc (bool enable) { _enable_macc = enable; STREAM_LOCK; return true; } bool CL3aImageProcessor::set_tonemapping (CLTonemappingMode wdr_mode) { _wdr_mode = wdr_mode; STREAM_LOCK; return true; } bool CL3aImageProcessor::set_tnr (uint32_t mode, uint8_t level) { XCAM_UNUSED (level); _tnr_mode = mode; STREAM_LOCK; if (_yuv_pipe.ptr ()) _yuv_pipe->set_tnr_enable (_tnr_mode & CL_TNR_TYPE_YUV); return true; } };