1 /*
2  * sample_smart_analysis.cpp - smart analysis sample code
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: Zong Wei <wei.zong@intel.com>
19  */
20 
21 #include <base/xcam_smart_description.h>
22 #include <base/xcam_buffer.h>
23 #include <xcam_std.h>
24 #include "aiq3a_utils.h"
25 #include "x3a_result_factory.h"
26 #include "smart_analyzer.h"
27 
28 using namespace XCam;
29 
30 #define DEFAULT_SAVE_FRAME_NAME "frame_buffer"
31 #define XSMART_ANALYSIS_CONTEXT_CAST(context)  ((XCamSmartAnalyerContext*)(context))
32 
33 class FrameSaver
34 {
35 public:
36     explicit FrameSaver (bool save, uint32_t interval, uint32_t count);
37     ~FrameSaver ();
38 
39     void save_frame (XCamVideoBuffer *buffer);
40 
enable_save_file(bool enable)41     void enable_save_file (bool enable) {
42         _save_file = enable;
43     }
set_interval(uint32_t inteval)44     void set_interval (uint32_t inteval) {
45         _interval = inteval;
46     }
set_frame_save(uint32_t frame_save)47     void set_frame_save (uint32_t frame_save) {
48         _frame_save = frame_save;
49     }
50 
51 private:
52     XCAM_DEAD_COPY (FrameSaver);
53     void open_file ();
54     void close_file ();
55 
56 private:
57     FILE *_file;
58     bool _save_file;
59     uint32_t _interval;
60     uint32_t _frame_save;
61     uint32_t _frame_count;
62     uint32_t _skip_frame_count;
63 
64 };
65 
FrameSaver(bool save,uint32_t interval,uint32_t count)66 FrameSaver::FrameSaver (bool save, uint32_t interval, uint32_t count)
67     : _file (NULL)
68     , _save_file (save)
69     , _interval (interval)
70     , _frame_save (count)
71     , _frame_count (0)
72     , _skip_frame_count (300)
73 {
74 }
75 
~FrameSaver()76 FrameSaver::~FrameSaver ()
77 {
78     close_file ();
79 }
80 
81 void
save_frame(XCamVideoBuffer * buffer)82 FrameSaver::save_frame (XCamVideoBuffer *buffer)
83 {
84     if (NULL == buffer) {
85         return;
86     }
87     if (!_save_file)
88         return ;
89 
90     if ((_frame_count++ % _interval) != 0)
91         return;
92 
93     if (_frame_count < _skip_frame_count)
94         return;
95 
96     if (_frame_count > (_frame_save * _interval + _skip_frame_count)) {
97         return;
98     }
99 
100     open_file ();
101 
102     if (!_file) {
103         XCAM_LOG_ERROR ("open file failed");
104         return;
105     }
106 
107     uint8_t *memory = xcam_video_buffer_map (buffer);
108     XCamVideoBufferPlanarInfo planar;
109     for (uint32_t index = 0; index < buffer->info.components; index++) {
110         xcam_video_buffer_get_planar_info (&buffer->info, &planar, index);
111         uint32_t line_bytes = planar.width * planar.pixel_bytes;
112 
113         for (uint32_t i = 0; i < planar.height; i++) {
114             if (fwrite (memory + buffer->info.offsets [index] + i * buffer->info.strides [index],
115                         1, line_bytes, _file) != line_bytes) {
116                 XCAM_LOG_ERROR ("write file failed, size doesn't match");
117                 return;
118             }
119         }
120     }
121     xcam_video_buffer_unmap (buffer);
122     close_file ();
123 }
124 
125 void
open_file()126 FrameSaver::open_file ()
127 {
128     if ((_file) && (_frame_save == 0))
129         return;
130 
131     char file_name[512];
132     if (_frame_save != 0) {
133         snprintf (file_name, sizeof(file_name), "%s%d%s", DEFAULT_SAVE_FRAME_NAME, _frame_count, ".yuv");
134     }
135 
136     _file = fopen(file_name, "wb");
137 }
138 
139 void
close_file()140 FrameSaver::close_file ()
141 {
142     if (_file)
143         fclose (_file);
144     _file = NULL;
145 }
146 
147 class SampleHandler
148 {
149 public:
150     explicit SampleHandler (const char *name = NULL);
151     virtual ~SampleHandler ();
152 
153     XCamReturn init (uint32_t width, uint32_t height, double framerate);
154     XCamReturn deinit ();
155     bool set_results_callback (AnalyzerCallback *callback);
156 
157     XCamReturn update_params (const XCamSmartAnalysisParam *params);
158     XCamReturn analyze (XCamVideoBuffer *buffer);
159 
160 private:
161     XCAM_DEAD_COPY (SampleHandler);
162 
163 private:
164     char                    *_name;
165     uint32_t                 _width;
166     uint32_t                 _height;
167     double                   _framerate;
168     AnalyzerCallback        *_callback;
169     SmartPtr<FrameSaver>    _frameSaver;
170 };
171 
SampleHandler(const char * name)172 SampleHandler::SampleHandler (const char *name)
173     : _name (NULL)
174     , _width (0)
175     , _height (0)
176     , _framerate (30.0)
177     , _callback (NULL)
178 {
179     if (name)
180         _name = strndup (name, XCAM_MAX_STR_SIZE);
181 
182     if (!_frameSaver.ptr ()) {
183         _frameSaver = new FrameSaver (true, 2, 16);
184     }
185 }
186 
~SampleHandler()187 SampleHandler::~SampleHandler ()
188 {
189     if (_name)
190         xcam_free (_name);
191 }
192 
193 XCamReturn
init(uint32_t width,uint32_t height,double framerate)194 SampleHandler::init (uint32_t width, uint32_t height, double framerate)
195 {
196     XCamReturn ret = XCAM_RETURN_NO_ERROR;
197     _width = width;
198     _height = height;
199     _framerate = framerate;
200 
201     return ret;
202 }
203 
204 XCamReturn
deinit()205 SampleHandler::deinit ()
206 {
207     XCamReturn ret = XCAM_RETURN_NO_ERROR;
208     return ret;
209 }
210 
211 bool
set_results_callback(AnalyzerCallback * callback)212 SampleHandler::set_results_callback (AnalyzerCallback *callback)
213 {
214     XCAM_ASSERT (!_callback);
215     _callback = callback;
216     return true;
217 }
218 
219 XCamReturn
update_params(const XCamSmartAnalysisParam * params)220 SampleHandler::update_params (const XCamSmartAnalysisParam *params)
221 {
222     XCAM_UNUSED (params);
223 
224     XCamReturn ret = XCAM_RETURN_NO_ERROR;
225     return ret;
226 }
227 
228 XCamReturn
analyze(XCamVideoBuffer * buffer)229 SampleHandler::analyze (XCamVideoBuffer *buffer)
230 {
231     XCAM_LOG_DEBUG ("Smart SampleHandler::analyze on ts:" XCAM_TIMESTAMP_FORMAT, XCAM_TIMESTAMP_ARGS (buffer->timestamp));
232     if (NULL == buffer) {
233         return XCAM_RETURN_ERROR_PARAM;
234     }
235     XCamReturn ret = XCAM_RETURN_NO_ERROR;
236 
237     XCAM_LOG_DEBUG ("format(0x%x), color_bits(%d)", buffer->info.format, buffer->info.color_bits);
238     XCAM_LOG_DEBUG ("size(%d), components(%d)", buffer->info.size, buffer->info.components);
239     XCAM_LOG_DEBUG ("width(%d), heitht(%d)", buffer->info.width, buffer->info.height);
240     XCAM_LOG_DEBUG ("aligned_width(%d), aligned_height(%d)", buffer->info.aligned_width, buffer->info.aligned_height);
241 
242     _frameSaver->save_frame (buffer);
243 
244     X3aResultList results;
245     XCam3aResultBrightness xcam3a_brightness_result;
246     xcam_mem_clear (xcam3a_brightness_result);
247     xcam3a_brightness_result.head.type =   XCAM_3A_RESULT_BRIGHTNESS;
248     xcam3a_brightness_result.head.process_type = XCAM_IMAGE_PROCESS_ALWAYS;
249     xcam3a_brightness_result.head.version = XCAM_VERSION;
250     xcam3a_brightness_result.brightness_level = 9.9;
251 
252     SmartPtr<X3aResult> brightness_result =
253         X3aResultFactory::instance ()->create_3a_result ((XCam3aResultHead*)&xcam3a_brightness_result);
254     results.push_back(brightness_result);
255 
256     if (_callback) {
257         if (XCAM_RETURN_NO_ERROR == ret) {
258             _callback->x3a_calculation_done (NULL, results);
259         } else {
260             _callback->x3a_calculation_failed (NULL, buffer->timestamp, "pre 3a analyze failed");
261         }
262     }
263 
264     return ret;
265 }
266 
267 class XCamSmartAnalyerContext
268     : public AnalyzerCallback
269 {
270 public:
271     XCamSmartAnalyerContext ();
272     ~XCamSmartAnalyerContext ();
273     bool setup_handler ();
get_handler()274     SmartPtr<SampleHandler> &get_handler () {
275         return _handler;
276     }
277 
278     uint32_t get_results (X3aResultList &results);
279 
280     // derive from AnalyzerCallback
281     virtual void x3a_calculation_done (XAnalyzer *analyzer, X3aResultList &results);
282 
283 private:
284     XCAM_DEAD_COPY (XCamSmartAnalyerContext);
285 
286 private:
287 // members
288     SmartPtr<SampleHandler> _handler;
289     Mutex                   _result_mutex;
290     X3aResultList           _results;
291 };
292 
XCamSmartAnalyerContext()293 XCamSmartAnalyerContext::XCamSmartAnalyerContext ()
294 {
295     setup_handler ();
296 }
297 
~XCamSmartAnalyerContext()298 XCamSmartAnalyerContext::~XCamSmartAnalyerContext ()
299 {
300     _handler->deinit ();
301 }
302 
303 bool
setup_handler()304 XCamSmartAnalyerContext::setup_handler ()
305 {
306     XCAM_ASSERT (!_handler.ptr ());
307     _handler = new SampleHandler ();
308     XCAM_ASSERT (_handler.ptr ());
309     _handler->set_results_callback (this);
310     return true;
311 }
312 
313 void
x3a_calculation_done(XAnalyzer * analyzer,X3aResultList & results)314 XCamSmartAnalyerContext::x3a_calculation_done (XAnalyzer *analyzer, X3aResultList &results)
315 {
316     XCAM_UNUSED (analyzer);
317     SmartLock  locker (_result_mutex);
318     _results.insert (_results.end (), results.begin (), results.end ());
319 }
320 
321 uint32_t
get_results(X3aResultList & results)322 XCamSmartAnalyerContext::get_results (X3aResultList &results)
323 {
324     uint32_t size = 0;
325     SmartLock  locker (_result_mutex);
326 
327     results.assign (_results.begin (), _results.end ());
328     size = _results.size ();
329     _results.clear ();
330 
331     return size;
332 }
333 
334 static XCamReturn
xcam_create_context(XCamSmartAnalysisContext ** context,uint32_t * async_mode,XcamPostResultsFunc post_func)335 xcam_create_context (XCamSmartAnalysisContext **context, uint32_t *async_mode, XcamPostResultsFunc post_func)
336 {
337     XCAM_ASSERT (context);
338     XCAM_UNUSED (post_func);
339     XCamSmartAnalyerContext *analysis_context = new XCamSmartAnalyerContext ();
340     *context = ((XCamSmartAnalysisContext*)(analysis_context));
341     *async_mode = false;
342 
343     return XCAM_RETURN_NO_ERROR;
344 }
345 
346 static XCamReturn
xcam_destroy_context(XCamSmartAnalysisContext * context)347 xcam_destroy_context (XCamSmartAnalysisContext *context)
348 {
349     XCamSmartAnalyerContext *analysis_context = XSMART_ANALYSIS_CONTEXT_CAST (context);
350     delete analysis_context;
351     return XCAM_RETURN_NO_ERROR;
352 }
353 
354 static XCamReturn
xcam_update_params(XCamSmartAnalysisContext * context,const XCamSmartAnalysisParam * params)355 xcam_update_params (XCamSmartAnalysisContext *context, const XCamSmartAnalysisParam *params)
356 {
357     XCamReturn ret = XCAM_RETURN_NO_ERROR;
358     XCamSmartAnalyerContext *analysis_context = XSMART_ANALYSIS_CONTEXT_CAST (context);
359     XCAM_ASSERT (analysis_context);
360 
361     SmartPtr<SampleHandler> handler = analysis_context->get_handler ();
362     XCAM_ASSERT (handler.ptr ());
363     XCAM_ASSERT (params);
364 
365     ret = handler->update_params (params);
366     if (ret != XCAM_RETURN_NO_ERROR) {
367         XCAM_LOG_WARNING ("update params failed");
368     }
369 
370     return ret;
371 }
372 
373 static XCamReturn
xcam_get_results(XCamSmartAnalysisContext * context,XCam3aResultHead * results[],uint32_t * res_count)374 xcam_get_results (XCamSmartAnalysisContext *context, XCam3aResultHead *results[], uint32_t *res_count)
375 {
376     XCamSmartAnalyerContext *analysis_context = XSMART_ANALYSIS_CONTEXT_CAST (context);
377     XCAM_ASSERT (analysis_context);
378     X3aResultList analysis_results;
379     uint32_t result_count = analysis_context->get_results (analysis_results);
380 
381     if (!result_count) {
382         *res_count = 0;
383         XCAM_LOG_DEBUG ("Smart Analysis return no result");
384         return XCAM_RETURN_NO_ERROR;
385     }
386 
387     // mark as static
388     static XCam3aResultHead *res_array[XCAM_3A_MAX_RESULT_COUNT];
389     XCAM_ASSERT (result_count < XCAM_3A_MAX_RESULT_COUNT);
390     result_count = translate_3a_results_to_xcam (analysis_results, res_array, XCAM_3A_MAX_RESULT_COUNT);
391 
392     for (uint32_t i = 0; i < result_count; ++i) {
393         results[i] = res_array[i];
394     }
395     *res_count = result_count;
396     XCAM_ASSERT (result_count > 0);
397 
398     return XCAM_RETURN_NO_ERROR;
399 }
400 
401 
402 static XCamReturn
xcam_analyze(XCamSmartAnalysisContext * context,XCamVideoBuffer * buffer,XCam3aResultHead * results[],uint32_t * res_count)403 xcam_analyze (XCamSmartAnalysisContext *context, XCamVideoBuffer *buffer, XCam3aResultHead *results[], uint32_t *res_count)
404 {
405     XCamReturn ret = XCAM_RETURN_NO_ERROR;
406     if (!buffer) {
407         return XCAM_RETURN_ERROR_PARAM;
408     }
409 
410     XCamSmartAnalyerContext *analysis_context = XSMART_ANALYSIS_CONTEXT_CAST (context);
411     XCAM_ASSERT (analysis_context);
412 
413     SmartPtr<SampleHandler> handler = analysis_context->get_handler ();
414     XCAM_ASSERT (handler.ptr ());
415 
416     ret = handler->analyze(buffer);
417     if (ret != XCAM_RETURN_NO_ERROR) {
418         XCAM_LOG_WARNING ("buffer analyze failed");
419     }
420 
421     xcam_get_results (context, results, res_count);
422     return ret;
423 }
424 
425 static void
xcam_free_results(XCamSmartAnalysisContext * context,XCam3aResultHead * results[],uint32_t res_count)426 xcam_free_results (XCamSmartAnalysisContext *context, XCam3aResultHead *results[], uint32_t res_count)
427 {
428     XCAM_UNUSED (context);
429     for (uint32_t i = 0; i < res_count; ++i) {
430         if (results[i])
431             free_3a_result (results[i]);
432     }
433 }
434 
435 XCAM_BEGIN_DECLARE
436 
437 XCamSmartAnalysisDescription xcam_smart_analysis_desciption = {
438     XCAM_VERSION,
439     sizeof (XCamSmartAnalysisDescription),
440     XCAM_SMART_PLUGIN_PRIORITY_DEFAULT,
441     "sample test",
442     xcam_create_context,
443     xcam_destroy_context,
444     xcam_update_params,
445     xcam_analyze,
446     xcam_free_results
447 };
448 
449 XCAM_END_DECLARE
450 
451