/* * 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 <wei.zong@intel.com> */ #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