/* * image_processor.h - 3a image processor * * Copyright (c) 2014-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 "image_processor.h" #include "xcam_thread.h" namespace XCam { void ImageProcessCallback::process_buffer_done (ImageProcessor *processor, const SmartPtr &buf) { XCAM_UNUSED (processor); XCAM_ASSERT (buf.ptr() && processor); int64_t ts = buf->get_timestamp(); XCAM_UNUSED (ts); XCAM_LOG_DEBUG ( "processor(%s) handled buffer(" XCAM_TIMESTAMP_FORMAT ") successfully", XCAM_STR(processor->get_name()), XCAM_TIMESTAMP_ARGS (ts)); } void ImageProcessCallback::process_buffer_failed (ImageProcessor *processor, const SmartPtr &buf) { XCAM_ASSERT (buf.ptr() && processor); int64_t ts = buf->get_timestamp(); XCAM_UNUSED (ts); XCAM_LOG_WARNING ( "processor(%s) handled buffer(" XCAM_TIMESTAMP_FORMAT ") failed", XCAM_STR(processor->get_name()), XCAM_TIMESTAMP_ARGS (ts)); } void ImageProcessCallback::process_image_result_done (ImageProcessor *processor, const SmartPtr &result) { XCAM_UNUSED (processor); XCAM_ASSERT (result.ptr() && processor); int64_t ts = result->get_timestamp(); XCAM_UNUSED (ts); XCAM_LOG_DEBUG ( "processor(%s) processed result(type:%d, timestamp:" XCAM_TIMESTAMP_FORMAT ") done", XCAM_STR(processor->get_name()), (int)result->get_type(), XCAM_TIMESTAMP_ARGS (ts)); } class ImageProcessorThread : public Thread { public: ImageProcessorThread (ImageProcessor *processor) : Thread ("image_processor") , _processor (processor) {} ~ImageProcessorThread () {} virtual bool loop (); private: ImageProcessor *_processor; }; bool ImageProcessorThread::loop () { XCamReturn ret = _processor->buffer_process_loop (); if (ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_ERROR_TIMEOUT) return true; return false; } class X3aResultsProcessThread : public Thread { typedef SafeList ResultQueue; public: X3aResultsProcessThread (ImageProcessor *processor) : Thread ("x3a_results_process_thread") , _processor (processor) {} ~X3aResultsProcessThread () {} XCamReturn push_result (SmartPtr &result) { _queue.push (result); return XCAM_RETURN_NO_ERROR; } void triger_stop () { _queue.pause_pop (); } virtual bool loop (); private: ImageProcessor *_processor; ResultQueue _queue; }; bool X3aResultsProcessThread::loop () { X3aResultList result_list; SmartPtr result; result = _queue.pop (-1); if (!result.ptr ()) return false; result_list.push_back (result); while ((result = _queue.pop (0)).ptr ()) { result_list.push_back (result); } XCamReturn ret = _processor->process_3a_results (result_list); if (ret != XCAM_RETURN_NO_ERROR) { XCAM_LOG_DEBUG ("processing 3a result failed"); } return true; } ImageProcessor::ImageProcessor (const char* name) : _name (NULL) , _callback (NULL) { if (name) _name = strndup (name, XCAM_MAX_STR_SIZE); _processor_thread = new ImageProcessorThread (this); _results_thread = new X3aResultsProcessThread (this); } ImageProcessor::~ImageProcessor () { if (_name) xcam_free (_name); } bool ImageProcessor::set_callback (ImageProcessCallback *callback) { XCAM_ASSERT (!_callback); _callback = callback; return true; } XCamReturn ImageProcessor::start() { XCamReturn ret = XCAM_RETURN_NO_ERROR; if (!_results_thread->start ()) { return XCAM_RETURN_ERROR_THREAD; } if (!_processor_thread->start ()) { return XCAM_RETURN_ERROR_THREAD; } ret = emit_start (); if (ret != XCAM_RETURN_NO_ERROR) { XCAM_LOG_WARNING ("ImageProcessor(%s) emit start failed", XCAM_STR (_name)); _video_buf_queue.pause_pop (); _results_thread->triger_stop (); _processor_thread->stop (); _results_thread->stop (); return ret; } XCAM_LOG_INFO ("ImageProcessor(%s) started", XCAM_STR (_name)); return XCAM_RETURN_NO_ERROR; } XCamReturn ImageProcessor::stop() { _video_buf_queue.pause_pop (); _results_thread->triger_stop (); emit_stop (); _processor_thread->stop (); _results_thread->stop (); XCAM_LOG_DEBUG ("ImageProcessor(%s) stopped", XCAM_STR (_name)); return XCAM_RETURN_NO_ERROR; } XCamReturn ImageProcessor::push_buffer (SmartPtr &buf) { if (_video_buf_queue.push (buf)) return XCAM_RETURN_NO_ERROR; XCAM_LOG_DEBUG ("processor push buffer failed"); return XCAM_RETURN_ERROR_UNKNOWN; } XCamReturn ImageProcessor::push_3a_results (X3aResultList &results) { XCAM_ASSERT (!results.empty ()); XCamReturn ret = XCAM_RETURN_NO_ERROR; for (X3aResultList::iterator i_res = results.begin(); i_res != results.end(); ++i_res) { SmartPtr &res = *i_res; ret = _results_thread->push_result (res); if (ret != XCAM_RETURN_NO_ERROR) break; } XCAM_FAIL_RETURN( WARNING, ret == XCAM_RETURN_NO_ERROR, ret, "processor(%s) push 3a results failed", XCAM_STR(get_name())); return XCAM_RETURN_NO_ERROR; } XCamReturn ImageProcessor::push_3a_result (SmartPtr &result) { XCamReturn ret = _results_thread->push_result (result); XCAM_FAIL_RETURN( WARNING, ret == XCAM_RETURN_NO_ERROR, ret, "processor(%s) push 3a result failed", XCAM_STR(get_name())); return XCAM_RETURN_NO_ERROR; } XCamReturn ImageProcessor::process_3a_results (X3aResultList &results) { X3aResultList valid_results; XCamReturn ret = XCAM_RETURN_NO_ERROR; filter_valid_results (results, valid_results); if (valid_results.empty()) return XCAM_RETURN_BYPASS; ret = apply_3a_results (valid_results); if (ret != XCAM_RETURN_NO_ERROR && ret != XCAM_RETURN_BYPASS) { XCAM_LOG_WARNING ("processor(%s) apply results failed", XCAM_STR(get_name())); return ret; } if (_callback) { for (X3aResultList::iterator i_res = valid_results.begin(); i_res != valid_results.end(); ++i_res) { SmartPtr &res = *i_res; _callback->process_image_result_done (this, res); } } return ret; } XCamReturn ImageProcessor::process_3a_result (SmartPtr &result) { X3aResultList valid_results; XCamReturn ret = XCAM_RETURN_NO_ERROR; if (!can_process_result(result)) return XCAM_RETURN_BYPASS; ret = apply_3a_result (result); if (ret != XCAM_RETURN_NO_ERROR && ret != XCAM_RETURN_BYPASS) { XCAM_LOG_WARNING ("processor(%s) apply result failed", XCAM_STR(get_name())); return ret; } if (_callback) { _callback->process_image_result_done (this, result); } return ret; } void ImageProcessor::filter_valid_results (X3aResultList &input, X3aResultList &valid_results) { for (X3aResultList::iterator i_res = input.begin(); i_res != input.end(); ) { SmartPtr &res = *i_res; if (can_process_result(res)) { valid_results.push_back (res); input.erase (i_res++); } else ++i_res; } } void ImageProcessor::notify_process_buffer_done (const SmartPtr &buf) { if (_callback) _callback->process_buffer_done (this, buf); } void ImageProcessor::notify_process_buffer_failed (const SmartPtr &buf) { if (_callback) _callback->process_buffer_failed (this, buf); } XCamReturn ImageProcessor::buffer_process_loop () { XCamReturn ret = XCAM_RETURN_NO_ERROR; SmartPtr new_buf; SmartPtr buf = _video_buf_queue.pop(); if (!buf.ptr()) return XCAM_RETURN_ERROR_MEM; ret = this->process_buffer (buf, new_buf); if (ret < XCAM_RETURN_NO_ERROR) { XCAM_LOG_DEBUG ("processing buffer failed"); notify_process_buffer_failed (buf); return ret; } if (new_buf.ptr ()) notify_process_buffer_done (new_buf); return XCAM_RETURN_NO_ERROR; } XCamReturn ImageProcessor::emit_start () { return XCAM_RETURN_NO_ERROR; } void ImageProcessor::emit_stop () { } };