| /* |
| * sample_smart_analysis.cpp - smart analysis sample code |
| * |
| * 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: Zong Wei <[email protected]> |
| */ |
| |
| #include <base/xcam_smart_description.h> |
| #include <base/xcam_buffer.h> |
| #include <xcam_std.h> |
| #include "aiq3a_utils.h" |
| #include "x3a_result_factory.h" |
| #include "smart_analyzer.h" |
| |
| using namespace XCam; |
| |
| #define DEFAULT_SAVE_FRAME_NAME "frame_buffer" |
| #define XSMART_ANALYSIS_CONTEXT_CAST(context) ((XCamSmartAnalyerContext*)(context)) |
| |
| class FrameSaver |
| { |
| public: |
| explicit FrameSaver (bool save, uint32_t interval, uint32_t count); |
| ~FrameSaver (); |
| |
| void save_frame (XCamVideoBuffer *buffer); |
| |
| void enable_save_file (bool enable) { |
| _save_file = enable; |
| } |
| void set_interval (uint32_t inteval) { |
| _interval = inteval; |
| } |
| void set_frame_save (uint32_t frame_save) { |
| _frame_save = frame_save; |
| } |
| |
| private: |
| XCAM_DEAD_COPY (FrameSaver); |
| void open_file (); |
| void close_file (); |
| |
| private: |
| FILE *_file; |
| bool _save_file; |
| uint32_t _interval; |
| uint32_t _frame_save; |
| uint32_t _frame_count; |
| uint32_t _skip_frame_count; |
| |
| }; |
| |
| FrameSaver::FrameSaver (bool save, uint32_t interval, uint32_t count) |
| : _file (NULL) |
| , _save_file (save) |
| , _interval (interval) |
| , _frame_save (count) |
| , _frame_count (0) |
| , _skip_frame_count (300) |
| { |
| } |
| |
| FrameSaver::~FrameSaver () |
| { |
| close_file (); |
| } |
| |
| void |
| FrameSaver::save_frame (XCamVideoBuffer *buffer) |
| { |
| if (NULL == buffer) { |
| return; |
| } |
| if (!_save_file) |
| return ; |
| |
| if ((_frame_count++ % _interval) != 0) |
| return; |
| |
| if (_frame_count < _skip_frame_count) |
| return; |
| |
| if (_frame_count > (_frame_save * _interval + _skip_frame_count)) { |
| return; |
| } |
| |
| open_file (); |
| |
| if (!_file) { |
| XCAM_LOG_ERROR ("open file failed"); |
| return; |
| } |
| |
| uint8_t *memory = xcam_video_buffer_map (buffer); |
| XCamVideoBufferPlanarInfo planar; |
| for (uint32_t index = 0; index < buffer->info.components; index++) { |
| xcam_video_buffer_get_planar_info (&buffer->info, &planar, index); |
| uint32_t line_bytes = planar.width * planar.pixel_bytes; |
| |
| for (uint32_t i = 0; i < planar.height; i++) { |
| if (fwrite (memory + buffer->info.offsets [index] + i * buffer->info.strides [index], |
| 1, line_bytes, _file) != line_bytes) { |
| XCAM_LOG_ERROR ("write file failed, size doesn't match"); |
| return; |
| } |
| } |
| } |
| xcam_video_buffer_unmap (buffer); |
| close_file (); |
| } |
| |
| void |
| FrameSaver::open_file () |
| { |
| if ((_file) && (_frame_save == 0)) |
| return; |
| |
| char file_name[512]; |
| if (_frame_save != 0) { |
| snprintf (file_name, sizeof(file_name), "%s%d%s", DEFAULT_SAVE_FRAME_NAME, _frame_count, ".yuv"); |
| } |
| |
| _file = fopen(file_name, "wb"); |
| } |
| |
| void |
| FrameSaver::close_file () |
| { |
| if (_file) |
| fclose (_file); |
| _file = NULL; |
| } |
| |
| class SampleHandler |
| { |
| public: |
| explicit SampleHandler (const char *name = NULL); |
| virtual ~SampleHandler (); |
| |
| XCamReturn init (uint32_t width, uint32_t height, double framerate); |
| XCamReturn deinit (); |
| bool set_results_callback (AnalyzerCallback *callback); |
| |
| XCamReturn update_params (const XCamSmartAnalysisParam *params); |
| XCamReturn analyze (XCamVideoBuffer *buffer); |
| |
| private: |
| XCAM_DEAD_COPY (SampleHandler); |
| |
| private: |
| char *_name; |
| uint32_t _width; |
| uint32_t _height; |
| double _framerate; |
| AnalyzerCallback *_callback; |
| SmartPtr<FrameSaver> _frameSaver; |
| }; |
| |
| SampleHandler::SampleHandler (const char *name) |
| : _name (NULL) |
| , _width (0) |
| , _height (0) |
| , _framerate (30.0) |
| , _callback (NULL) |
| { |
| if (name) |
| _name = strndup (name, XCAM_MAX_STR_SIZE); |
| |
| if (!_frameSaver.ptr ()) { |
| _frameSaver = new FrameSaver (true, 2, 16); |
| } |
| } |
| |
| SampleHandler::~SampleHandler () |
| { |
| if (_name) |
| xcam_free (_name); |
| } |
| |
| XCamReturn |
| SampleHandler::init (uint32_t width, uint32_t height, double framerate) |
| { |
| XCamReturn ret = XCAM_RETURN_NO_ERROR; |
| _width = width; |
| _height = height; |
| _framerate = framerate; |
| |
| return ret; |
| } |
| |
| XCamReturn |
| SampleHandler::deinit () |
| { |
| XCamReturn ret = XCAM_RETURN_NO_ERROR; |
| return ret; |
| } |
| |
| bool |
| SampleHandler::set_results_callback (AnalyzerCallback *callback) |
| { |
| XCAM_ASSERT (!_callback); |
| _callback = callback; |
| return true; |
| } |
| |
| XCamReturn |
| SampleHandler::update_params (const XCamSmartAnalysisParam *params) |
| { |
| XCAM_UNUSED (params); |
| |
| XCamReturn ret = XCAM_RETURN_NO_ERROR; |
| return ret; |
| } |
| |
| XCamReturn |
| SampleHandler::analyze (XCamVideoBuffer *buffer) |
| { |
| XCAM_LOG_DEBUG ("Smart SampleHandler::analyze on ts:" XCAM_TIMESTAMP_FORMAT, XCAM_TIMESTAMP_ARGS (buffer->timestamp)); |
| if (NULL == buffer) { |
| return XCAM_RETURN_ERROR_PARAM; |
| } |
| XCamReturn ret = XCAM_RETURN_NO_ERROR; |
| |
| XCAM_LOG_DEBUG ("format(0x%x), color_bits(%d)", buffer->info.format, buffer->info.color_bits); |
| XCAM_LOG_DEBUG ("size(%d), components(%d)", buffer->info.size, buffer->info.components); |
| XCAM_LOG_DEBUG ("width(%d), heitht(%d)", buffer->info.width, buffer->info.height); |
| XCAM_LOG_DEBUG ("aligned_width(%d), aligned_height(%d)", buffer->info.aligned_width, buffer->info.aligned_height); |
| |
| _frameSaver->save_frame (buffer); |
| |
| X3aResultList results; |
| 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 = 9.9; |
| |
| SmartPtr<X3aResult> brightness_result = |
| X3aResultFactory::instance ()->create_3a_result ((XCam3aResultHead*)&xcam3a_brightness_result); |
| results.push_back(brightness_result); |
| |
| if (_callback) { |
| if (XCAM_RETURN_NO_ERROR == ret) { |
| _callback->x3a_calculation_done (NULL, results); |
| } else { |
| _callback->x3a_calculation_failed (NULL, buffer->timestamp, "pre 3a analyze failed"); |
| } |
| } |
| |
| return ret; |
| } |
| |
| class XCamSmartAnalyerContext |
| : public AnalyzerCallback |
| { |
| public: |
| XCamSmartAnalyerContext (); |
| ~XCamSmartAnalyerContext (); |
| bool setup_handler (); |
| SmartPtr<SampleHandler> &get_handler () { |
| return _handler; |
| } |
| |
| uint32_t get_results (X3aResultList &results); |
| |
| // derive from AnalyzerCallback |
| virtual void x3a_calculation_done (XAnalyzer *analyzer, X3aResultList &results); |
| |
| private: |
| XCAM_DEAD_COPY (XCamSmartAnalyerContext); |
| |
| private: |
| // members |
| SmartPtr<SampleHandler> _handler; |
| Mutex _result_mutex; |
| X3aResultList _results; |
| }; |
| |
| XCamSmartAnalyerContext::XCamSmartAnalyerContext () |
| { |
| setup_handler (); |
| } |
| |
| XCamSmartAnalyerContext::~XCamSmartAnalyerContext () |
| { |
| _handler->deinit (); |
| } |
| |
| bool |
| XCamSmartAnalyerContext::setup_handler () |
| { |
| XCAM_ASSERT (!_handler.ptr ()); |
| _handler = new SampleHandler (); |
| XCAM_ASSERT (_handler.ptr ()); |
| _handler->set_results_callback (this); |
| return true; |
| } |
| |
| void |
| XCamSmartAnalyerContext::x3a_calculation_done (XAnalyzer *analyzer, X3aResultList &results) |
| { |
| XCAM_UNUSED (analyzer); |
| SmartLock locker (_result_mutex); |
| _results.insert (_results.end (), results.begin (), results.end ()); |
| } |
| |
| uint32_t |
| XCamSmartAnalyerContext::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 XCamReturn |
| xcam_create_context (XCamSmartAnalysisContext **context, uint32_t *async_mode, XcamPostResultsFunc post_func) |
| { |
| XCAM_ASSERT (context); |
| XCAM_UNUSED (post_func); |
| XCamSmartAnalyerContext *analysis_context = new XCamSmartAnalyerContext (); |
| *context = ((XCamSmartAnalysisContext*)(analysis_context)); |
| *async_mode = false; |
| |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| static XCamReturn |
| xcam_destroy_context (XCamSmartAnalysisContext *context) |
| { |
| XCamSmartAnalyerContext *analysis_context = XSMART_ANALYSIS_CONTEXT_CAST (context); |
| delete analysis_context; |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| static XCamReturn |
| xcam_update_params (XCamSmartAnalysisContext *context, const XCamSmartAnalysisParam *params) |
| { |
| XCamReturn ret = XCAM_RETURN_NO_ERROR; |
| XCamSmartAnalyerContext *analysis_context = XSMART_ANALYSIS_CONTEXT_CAST (context); |
| XCAM_ASSERT (analysis_context); |
| |
| SmartPtr<SampleHandler> handler = analysis_context->get_handler (); |
| XCAM_ASSERT (handler.ptr ()); |
| XCAM_ASSERT (params); |
| |
| ret = handler->update_params (params); |
| if (ret != XCAM_RETURN_NO_ERROR) { |
| XCAM_LOG_WARNING ("update params failed"); |
| } |
| |
| return ret; |
| } |
| |
| static XCamReturn |
| xcam_get_results (XCamSmartAnalysisContext *context, XCam3aResultHead *results[], uint32_t *res_count) |
| { |
| XCamSmartAnalyerContext *analysis_context = XSMART_ANALYSIS_CONTEXT_CAST (context); |
| XCAM_ASSERT (analysis_context); |
| X3aResultList analysis_results; |
| uint32_t result_count = analysis_context->get_results (analysis_results); |
| |
| if (!result_count) { |
| *res_count = 0; |
| XCAM_LOG_DEBUG ("Smart Analysis return no result"); |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| // mark as static |
| static XCam3aResultHead *res_array[XCAM_3A_MAX_RESULT_COUNT]; |
| XCAM_ASSERT (result_count < XCAM_3A_MAX_RESULT_COUNT); |
| result_count = translate_3a_results_to_xcam (analysis_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 XCamReturn |
| xcam_analyze (XCamSmartAnalysisContext *context, XCamVideoBuffer *buffer, XCam3aResultHead *results[], uint32_t *res_count) |
| { |
| XCamReturn ret = XCAM_RETURN_NO_ERROR; |
| if (!buffer) { |
| return XCAM_RETURN_ERROR_PARAM; |
| } |
| |
| XCamSmartAnalyerContext *analysis_context = XSMART_ANALYSIS_CONTEXT_CAST (context); |
| XCAM_ASSERT (analysis_context); |
| |
| SmartPtr<SampleHandler> handler = analysis_context->get_handler (); |
| XCAM_ASSERT (handler.ptr ()); |
| |
| ret = handler->analyze(buffer); |
| if (ret != XCAM_RETURN_NO_ERROR) { |
| XCAM_LOG_WARNING ("buffer analyze failed"); |
| } |
| |
| xcam_get_results (context, results, res_count); |
| return ret; |
| } |
| |
| static void |
| xcam_free_results (XCamSmartAnalysisContext *context, XCam3aResultHead *results[], uint32_t res_count) |
| { |
| XCAM_UNUSED (context); |
| for (uint32_t i = 0; i < res_count; ++i) { |
| if (results[i]) |
| free_3a_result (results[i]); |
| } |
| } |
| |
| XCAM_BEGIN_DECLARE |
| |
| XCamSmartAnalysisDescription xcam_smart_analysis_desciption = { |
| XCAM_VERSION, |
| sizeof (XCamSmartAnalysisDescription), |
| XCAM_SMART_PLUGIN_PRIORITY_DEFAULT, |
| "sample test", |
| xcam_create_context, |
| xcam_destroy_context, |
| xcam_update_params, |
| xcam_analyze, |
| xcam_free_results |
| }; |
| |
| XCAM_END_DECLARE |
| |