1/*
2 * x3a_analyzer_simple.cpp - a simple 3a analyzer
3 *
4 *  Copyright (c) 2015 Intel Corporation
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *      http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * Author: Wind Yuan <feng.yuan@intel.com>
19 */
20
21#include "x3a_analyzer_simple.h"
22
23namespace XCam {
24
25#define SIMPLE_MIN_TARGET_EXPOSURE_TIME  5000 //5ms
26#define SIMPLE_MAX_TARGET_EXPOSURE_TIME  33000 //33ms
27#define SIMPLE_DEFAULT_BLACK_LEVEL       0.05
28
29class SimpleAeHandler
30    : public AeHandler
31{
32public:
33    SimpleAeHandler (X3aAnalyzerSimple *analyzer)
34        : _analyzer (analyzer)
35    {}
36    ~SimpleAeHandler () {}
37
38    virtual XCamReturn analyze (X3aResultList &output) {
39        return _analyzer->analyze_ae (output);
40    }
41private:
42    X3aAnalyzerSimple *_analyzer;
43};
44
45class SimpleAwbHandler
46    : public AwbHandler
47{
48public:
49    SimpleAwbHandler (X3aAnalyzerSimple *analyzer)
50        : _analyzer (analyzer)
51    {}
52    ~SimpleAwbHandler () {}
53
54    virtual XCamReturn analyze (X3aResultList &output) {
55        return _analyzer->analyze_awb (output);
56    }
57private:
58    X3aAnalyzerSimple *_analyzer;
59
60};
61
62class SimpleAfHandler
63    : public AfHandler
64{
65public:
66    SimpleAfHandler (X3aAnalyzerSimple *analyzer)
67        : _analyzer (analyzer)
68    {}
69    ~SimpleAfHandler () {}
70
71    virtual XCamReturn analyze (X3aResultList &output) {
72        return _analyzer->analyze_af (output);
73    }
74
75private:
76    X3aAnalyzerSimple *_analyzer;
77};
78
79class SimpleCommonHandler
80    : public CommonHandler
81{
82public:
83    SimpleCommonHandler (X3aAnalyzerSimple *analyzer)
84        : _analyzer (analyzer)
85    {}
86    ~SimpleCommonHandler () {}
87
88    virtual XCamReturn analyze (X3aResultList &output) {
89        XCAM_UNUSED (output);
90        return XCAM_RETURN_NO_ERROR;
91    }
92
93private:
94    X3aAnalyzerSimple *_analyzer;
95};
96
97X3aAnalyzerSimple::X3aAnalyzerSimple ()
98    : X3aAnalyzer ("X3aAnalyzerSimple")
99    , _last_target_exposure ((double)SIMPLE_MIN_TARGET_EXPOSURE_TIME)
100    , _is_ae_started (false)
101    , _ae_calculation_interval (0)
102{
103}
104
105X3aAnalyzerSimple::~X3aAnalyzerSimple ()
106{
107}
108
109SmartPtr<AeHandler>
110X3aAnalyzerSimple::create_ae_handler ()
111{
112    SimpleAeHandler *handler = new SimpleAeHandler (this);
113    return handler;
114}
115
116SmartPtr<AwbHandler>
117X3aAnalyzerSimple::create_awb_handler ()
118{
119    SimpleAwbHandler *handler = new SimpleAwbHandler (this);
120    return handler;
121}
122
123SmartPtr<AfHandler>
124X3aAnalyzerSimple::create_af_handler ()
125{
126    SimpleAfHandler *handler = new SimpleAfHandler (this);
127    return handler;
128}
129
130SmartPtr<CommonHandler>
131X3aAnalyzerSimple::create_common_handler ()
132{
133    SimpleCommonHandler *handler = new SimpleCommonHandler (this);
134    return handler;
135}
136
137XCamReturn
138X3aAnalyzerSimple::configure_3a ()
139{
140    _is_ae_started = false;
141    _ae_calculation_interval = 0;
142    return XCAM_RETURN_NO_ERROR;
143}
144
145XCamReturn
146X3aAnalyzerSimple::pre_3a_analyze (SmartPtr<X3aStats> &stats)
147{
148    _current_stats = stats;
149    return XCAM_RETURN_NO_ERROR;
150}
151
152XCamReturn
153X3aAnalyzerSimple::post_3a_analyze (X3aResultList &results)
154{
155    _current_stats.release ();
156
157    XCam3aResultBlackLevel black_level;
158    SmartPtr<X3aBlackLevelResult> bl_result = new X3aBlackLevelResult (XCAM_3A_RESULT_BLACK_LEVEL);
159
160    xcam_mem_clear (black_level);
161    black_level.r_level = SIMPLE_DEFAULT_BLACK_LEVEL;
162    black_level.gr_level = SIMPLE_DEFAULT_BLACK_LEVEL;
163    black_level.gb_level = SIMPLE_DEFAULT_BLACK_LEVEL;
164    black_level.b_level = SIMPLE_DEFAULT_BLACK_LEVEL;
165    bl_result->set_standard_result (black_level);
166    results.push_back (bl_result);
167
168    return XCAM_RETURN_NO_ERROR;
169}
170
171XCamReturn
172X3aAnalyzerSimple::analyze_awb (X3aResultList &output)
173{
174    const XCam3AStats *stats = _current_stats->get_stats ();
175    double sum_r = 0.0, sum_gr = 0.0, sum_gb = 0.0, sum_b = 0.0;
176    double avg_r = 0.0, avg_gr = 0.0, avg_gb = 0.0, avg_b = 0.0;
177    double target_avg = 0.0;
178    XCam3aResultWhiteBalance wb;
179
180    xcam_mem_clear (wb);
181    XCAM_ASSERT (stats);
182
183    // calculate avg r, gr, gb, b
184    for (uint32_t i = 0; i < stats->info.height; ++i)
185        for (uint32_t j = 0; j < stats->info.width; ++j) {
186            sum_r += (double)(stats->stats[i * stats->info.aligned_width + j].avg_r);
187            sum_gr += (double)(stats->stats[i * stats->info.aligned_width + j].avg_gr);
188            sum_gb += (double)(stats->stats[i * stats->info.aligned_width + j].avg_gb);
189            sum_b += (double)(stats->stats[i * stats->info.aligned_width + j].avg_b);
190        }
191
192    avg_r = sum_r / (stats->info.width * stats->info.height);
193    avg_gr = sum_gr / (stats->info.width * stats->info.height);
194    avg_gb = sum_gb / (stats->info.width * stats->info.height);
195    avg_b = sum_b / (stats->info.width * stats->info.height);
196
197    target_avg =  (avg_gr + avg_gb) / 2;
198    wb.r_gain = target_avg / avg_r;
199    wb.b_gain = target_avg / avg_b;
200    wb.gr_gain = 1.0;
201    wb.gb_gain = 1.0;
202
203    SmartPtr<X3aWhiteBalanceResult> result = new X3aWhiteBalanceResult (XCAM_3A_RESULT_WHITE_BALANCE);
204    result->set_standard_result (wb);
205    output.push_back (result);
206
207    XCAM_LOG_DEBUG ("X3aAnalyzerSimple analyze awb, r:%f, gr:%f, gb:%f, b:%f",
208                    wb.r_gain, wb.gr_gain, wb.gb_gain, wb.b_gain);
209
210    return XCAM_RETURN_NO_ERROR;
211}
212
213XCamReturn
214X3aAnalyzerSimple::analyze_ae (X3aResultList &output)
215{
216    static const uint32_t expect_y_mean = 110;
217
218    const XCam3AStats *stats = _current_stats->get_stats ();
219    XCAM_FAIL_RETURN(
220        WARNING,
221        stats,
222        XCAM_RETURN_ERROR_UNKNOWN,
223        "failed to get XCam3AStats");
224
225    double sum_y = 0.0;
226    double target_exposure = 1.0;
227    SmartPtr<X3aExposureResult> result = new X3aExposureResult (XCAM_3A_RESULT_EXPOSURE);
228    XCam3aResultExposure exposure;
229
230    xcam_mem_clear (exposure);
231    exposure.digital_gain = 1.0;
232
233    if (!_is_ae_started) {
234        _last_target_exposure = SIMPLE_MIN_TARGET_EXPOSURE_TIME;
235        exposure.exposure_time = _last_target_exposure;
236        exposure.analog_gain = 1.0;
237
238        result->set_standard_result (exposure);
239        output.push_back (result);
240        _is_ae_started = true;
241        return XCAM_RETURN_NO_ERROR;
242    }
243
244    if (_ae_calculation_interval % 10 == 0) {
245        for (uint32_t i = 0; i < stats->info.height; ++i)
246            for (uint32_t j = 0; j < stats->info.width; ++j) {
247                sum_y += (double)(stats->stats[i * stats->info.aligned_width + j].avg_y);
248            }
249        sum_y /= (stats->info.width * stats->info.height);
250        target_exposure = (expect_y_mean / sum_y) * _last_target_exposure;
251        target_exposure = XCAM_MAX (target_exposure, SIMPLE_MIN_TARGET_EXPOSURE_TIME);
252
253        if (target_exposure > SIMPLE_MAX_TARGET_EXPOSURE_TIME * 255)
254            target_exposure = SIMPLE_MAX_TARGET_EXPOSURE_TIME * 255;
255
256        if (target_exposure > SIMPLE_MAX_TARGET_EXPOSURE_TIME) {
257            exposure.exposure_time = SIMPLE_MAX_TARGET_EXPOSURE_TIME;
258            exposure.analog_gain = target_exposure / exposure.exposure_time;
259        } else {
260            exposure.exposure_time = target_exposure;
261            exposure.analog_gain = 1.0;
262        }
263
264        result->set_standard_result (exposure);
265        output.push_back (result);
266        _last_target_exposure = target_exposure;
267    }
268
269    _ae_calculation_interval++;
270
271    return XCAM_RETURN_NO_ERROR;
272}
273
274XCamReturn X3aAnalyzerSimple::analyze_af (X3aResultList &output)
275{
276    XCAM_UNUSED (output);
277    return XCAM_RETURN_NO_ERROR;
278}
279
280};
281