| /* |
| * 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 <[email protected]> |
| */ |
| |
| #include "image_processor.h" |
| #include "xcam_thread.h" |
| |
| namespace XCam { |
| |
| void |
| ImageProcessCallback::process_buffer_done (ImageProcessor *processor, const SmartPtr<VideoBuffer> &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<VideoBuffer> &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<X3aResult> &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<X3aResult> ResultQueue; |
| public: |
| X3aResultsProcessThread (ImageProcessor *processor) |
| : Thread ("x3a_results_process_thread") |
| , _processor (processor) |
| {} |
| ~X3aResultsProcessThread () {} |
| |
| XCamReturn push_result (SmartPtr<X3aResult> &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<X3aResult> 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<VideoBuffer> &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<X3aResult> &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<X3aResult> &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<X3aResult> &res = *i_res; |
| _callback->process_image_result_done (this, res); |
| } |
| } |
| |
| return ret; |
| } |
| |
| XCamReturn |
| ImageProcessor::process_3a_result (SmartPtr<X3aResult> &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<X3aResult> &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<VideoBuffer> &buf) |
| { |
| if (_callback) |
| _callback->process_buffer_done (this, buf); |
| } |
| |
| void |
| ImageProcessor::notify_process_buffer_failed (const SmartPtr<VideoBuffer> &buf) |
| { |
| if (_callback) |
| _callback->process_buffer_failed (this, buf); |
| } |
| |
| XCamReturn |
| ImageProcessor::buffer_process_loop () |
| { |
| XCamReturn ret = XCAM_RETURN_NO_ERROR; |
| SmartPtr<VideoBuffer> new_buf; |
| SmartPtr<VideoBuffer> 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 () |
| { |
| } |
| |
| }; |