/*
|
* device_manager.h - device manager
|
*
|
* 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 <feng.yuan@intel.com>
|
*/
|
|
#include "device_manager.h"
|
#include "poll_thread.h"
|
#include "xcam_thread.h"
|
#include "x3a_image_process_center.h"
|
#include "x3a_analyzer_manager.h"
|
|
#define XCAM_FAILED_STOP(exp, msg, ...) \
|
if ((exp) != XCAM_RETURN_NO_ERROR) { \
|
XCAM_LOG_ERROR (msg, ## __VA_ARGS__); \
|
stop (); \
|
return ret; \
|
}
|
|
namespace XCam {
|
|
class MessageThread
|
: public Thread
|
{
|
public:
|
explicit MessageThread (DeviceManager *dev_manager)
|
: Thread ("MessageThread")
|
, _manager (dev_manager)
|
{}
|
|
protected:
|
virtual bool loop ();
|
|
DeviceManager *_manager;
|
};
|
|
bool
|
MessageThread::loop()
|
{
|
XCamReturn ret = _manager->message_loop();
|
if (ret == XCAM_RETURN_NO_ERROR || ret == XCAM_RETURN_ERROR_TIMEOUT)
|
return true;
|
|
return false;
|
}
|
|
XCamMessage::XCamMessage (XCamMessageType type, int64_t timestamp, const char *message)
|
: timestamp (timestamp)
|
, msg_id (type)
|
, msg (NULL)
|
{
|
if (message)
|
this->msg = strndup (message, XCAM_MAX_STR_SIZE);
|
}
|
|
XCamMessage::~XCamMessage ()
|
{
|
if (msg)
|
xcam_free (msg);
|
}
|
|
DeviceManager::DeviceManager()
|
: _has_3a (true)
|
, _is_running (false)
|
{
|
_3a_process_center = new X3aImageProcessCenter;
|
XCAM_LOG_DEBUG ("~DeviceManager construction");
|
}
|
|
DeviceManager::~DeviceManager()
|
{
|
XCAM_LOG_DEBUG ("~DeviceManager destruction");
|
}
|
|
bool
|
DeviceManager::set_capture_device (SmartPtr<V4l2Device> device)
|
{
|
if (is_running())
|
return false;
|
|
XCAM_ASSERT (device.ptr () && !_device.ptr ());
|
_device = device;
|
return true;
|
}
|
|
bool
|
DeviceManager::set_event_device (SmartPtr<V4l2SubDevice> device)
|
{
|
if (is_running())
|
return false;
|
|
XCAM_ASSERT (device.ptr () && !_subdevice.ptr ());
|
_subdevice = device;
|
return true;
|
}
|
|
bool
|
DeviceManager::set_3a_analyzer (SmartPtr<X3aAnalyzer> analyzer)
|
{
|
if (is_running())
|
return false;
|
|
XCAM_ASSERT (analyzer.ptr () && !_3a_analyzer.ptr ());
|
_3a_analyzer = analyzer;
|
|
return true;
|
}
|
|
bool
|
DeviceManager::set_smart_analyzer (SmartPtr<SmartAnalyzer> analyzer)
|
{
|
if (is_running())
|
return false;
|
|
XCAM_ASSERT (analyzer.ptr () && !_smart_analyzer.ptr ());
|
_smart_analyzer = analyzer;
|
|
return true;
|
}
|
|
bool
|
DeviceManager::add_image_processor (SmartPtr<ImageProcessor> processor)
|
{
|
if (is_running())
|
return false;
|
|
XCAM_ASSERT (processor.ptr ());
|
return _3a_process_center->insert_processor (processor);
|
}
|
|
bool
|
DeviceManager::set_poll_thread (SmartPtr<PollThread> thread)
|
{
|
if (is_running ())
|
return false;
|
|
XCAM_ASSERT (thread.ptr () && !_poll_thread.ptr ());
|
_poll_thread = thread;
|
return true;
|
}
|
|
XCamReturn
|
DeviceManager::start ()
|
{
|
XCamReturn ret = XCAM_RETURN_NO_ERROR;
|
|
// start device
|
XCAM_ASSERT (_device->is_opened());
|
if (!_device.ptr() || !_device->is_opened()) {
|
XCAM_FAILED_STOP (ret = XCAM_RETURN_ERROR_FILE, "capture device not ready");
|
}
|
XCAM_FAILED_STOP (ret = _device->start(), "capture device start failed");
|
|
//start subdevice
|
//XCAM_ASSERT (_subdevice->is_opened());
|
if (_subdevice.ptr()) {
|
if (!_subdevice->is_opened())
|
XCAM_FAILED_STOP (ret = XCAM_RETURN_ERROR_FILE, "event device not ready");
|
XCAM_FAILED_STOP (ret = _subdevice->start(), "start event device failed");
|
}
|
|
if (_has_3a) {
|
// Initialize and start analyzer
|
uint32_t width = 0, height = 0;
|
uint32_t fps_n = 0, fps_d = 0;
|
double framerate = 30.0;
|
|
if (!_3a_analyzer.ptr()) {
|
_3a_analyzer = X3aAnalyzerManager::instance()->create_analyzer();
|
if (!_3a_analyzer.ptr()) {
|
XCAM_FAILED_STOP (ret = XCAM_RETURN_ERROR_PARAM, "create analyzer failed");
|
}
|
}
|
if (_3a_analyzer->prepare_handlers () != XCAM_RETURN_NO_ERROR) {
|
XCAM_FAILED_STOP (ret = XCAM_RETURN_ERROR_PARAM, "prepare analyzer handler failed");
|
}
|
_3a_analyzer->set_results_callback (this);
|
|
_device->get_size (width, height);
|
_device->get_framerate (fps_n, fps_d);
|
if (fps_d)
|
framerate = (double)fps_n / (double)fps_d;
|
XCAM_FAILED_STOP (
|
ret = _3a_analyzer->init (width, height, framerate),
|
"initialize analyzer failed");
|
|
XCAM_FAILED_STOP (ret = _3a_analyzer->start (), "start analyzer failed");
|
|
if (_smart_analyzer.ptr()) {
|
if (_smart_analyzer->prepare_handlers () != XCAM_RETURN_NO_ERROR) {
|
XCAM_LOG_INFO ("prepare smart analyzer handler failed");
|
}
|
_smart_analyzer->set_results_callback (this);
|
if (_smart_analyzer->init (width, height, framerate) != XCAM_RETURN_NO_ERROR) {
|
XCAM_LOG_INFO ("initialize smart analyzer failed");
|
}
|
if (_smart_analyzer->start () != XCAM_RETURN_NO_ERROR) {
|
XCAM_LOG_INFO ("start smart analyzer failed");
|
}
|
}
|
|
if (!_3a_process_center->has_processors ()) {
|
XCAM_LOG_ERROR ("image processors empty");
|
}
|
|
_3a_process_center->set_image_callback(this);
|
XCAM_FAILED_STOP (ret = _3a_process_center->start (), "3A process center start failed");
|
|
}
|
|
//Initialize and start poll thread
|
XCAM_ASSERT (_poll_thread.ptr ());
|
_poll_thread->set_capture_device (_device);
|
if (_subdevice.ptr ())
|
_poll_thread->set_event_device (_subdevice);
|
_poll_thread->set_poll_callback (this);
|
_poll_thread->set_stats_callback (this);
|
|
XCAM_FAILED_STOP (ret = _poll_thread->start(), "start poll failed");
|
|
_is_running = true;
|
|
XCAM_LOG_DEBUG ("Device manager started");
|
return XCAM_RETURN_NO_ERROR;
|
}
|
|
XCamReturn
|
DeviceManager::stop ()
|
{
|
_is_running = false;
|
|
if (_poll_thread.ptr())
|
_poll_thread->stop ();
|
|
if (_3a_analyzer.ptr()) {
|
_3a_analyzer->stop ();
|
_3a_analyzer->deinit ();
|
}
|
if (_smart_analyzer.ptr()) {
|
_smart_analyzer->stop ();
|
_smart_analyzer->deinit ();
|
}
|
|
if (_3a_process_center.ptr())
|
_3a_process_center->stop ();
|
|
if (_subdevice.ptr ())
|
_subdevice->stop ();
|
|
_device->stop ();
|
|
_poll_thread.release ();
|
|
XCAM_LOG_DEBUG ("Device manager stopped");
|
return XCAM_RETURN_NO_ERROR;
|
}
|
|
XCamReturn
|
DeviceManager::x3a_stats_ready (const SmartPtr<X3aStats> &stats)
|
{
|
XCamReturn ret = XCAM_RETURN_NO_ERROR;
|
X3aResultList results;
|
XCAM_ASSERT (_3a_analyzer.ptr());
|
|
ret = _3a_analyzer->push_3a_stats (stats);
|
XCAM_FAIL_RETURN (ERROR,
|
ret == XCAM_RETURN_NO_ERROR,
|
ret,
|
"analyze 3a statistics failed");
|
|
return XCAM_RETURN_NO_ERROR;
|
}
|
|
XCamReturn
|
DeviceManager::dvs_stats_ready ()
|
{
|
XCAM_ASSERT (false);
|
// TODO
|
return XCAM_RETURN_NO_ERROR;
|
}
|
|
XCamReturn
|
DeviceManager::scaled_image_ready (const SmartPtr<VideoBuffer> &buffer)
|
{
|
XCamReturn ret = XCAM_RETURN_NO_ERROR;
|
if (!_smart_analyzer.ptr()) {
|
return XCAM_RETURN_NO_ERROR;
|
}
|
|
ret = _smart_analyzer->push_buffer (buffer);
|
XCAM_FAIL_RETURN (
|
ERROR, ret == XCAM_RETURN_NO_ERROR, ret,
|
"push frame buffer failed");
|
|
return XCAM_RETURN_NO_ERROR;
|
}
|
|
|
XCamReturn
|
DeviceManager::poll_buffer_ready (SmartPtr<VideoBuffer> &buf)
|
{
|
if (_has_3a) {
|
if (_3a_process_center->put_buffer (buf) == false)
|
return XCAM_RETURN_ERROR_UNKNOWN;
|
}
|
return XCAM_RETURN_NO_ERROR;
|
}
|
|
XCamReturn
|
DeviceManager::poll_buffer_failed (int64_t timestamp, const char *msg)
|
{
|
post_message (XCAM_MESSAGE_BUF_ERROR, timestamp, msg);
|
return XCAM_RETURN_NO_ERROR;
|
}
|
|
void
|
DeviceManager::x3a_calculation_done (XAnalyzer *analyzer, X3aResultList &results)
|
{
|
XCamReturn ret = _3a_process_center->put_3a_results (results);
|
if (ret != XCAM_RETURN_NO_ERROR && ret != XCAM_RETURN_BYPASS) {
|
XCAM_LOG_WARNING ("apply 3a results failed");
|
return;
|
}
|
AnalyzerCallback::x3a_calculation_done (analyzer, results);
|
}
|
|
void
|
DeviceManager::x3a_calculation_failed (XAnalyzer *analyzer, int64_t timestamp, const char *msg)
|
{
|
AnalyzerCallback::x3a_calculation_failed (analyzer, timestamp, msg);
|
}
|
|
void
|
DeviceManager::process_buffer_done (ImageProcessor *processor, const SmartPtr<VideoBuffer> &buf)
|
{
|
ImageProcessCallback::process_buffer_done (processor, buf);
|
handle_buffer (buf);
|
}
|
|
void
|
DeviceManager::process_buffer_failed (ImageProcessor *processor, const SmartPtr<VideoBuffer> &buf)
|
{
|
ImageProcessCallback::process_buffer_failed (processor, buf);
|
}
|
|
void
|
DeviceManager::process_image_result_done (ImageProcessor *processor, const SmartPtr<X3aResult> &result)
|
{
|
ImageProcessCallback::process_image_result_done (processor, result);
|
}
|
|
void
|
DeviceManager::post_message (XCamMessageType type, int64_t timestamp, const char *msg)
|
{
|
SmartPtr<XCamMessage> new_msg = new XCamMessage (type, timestamp, msg);
|
_msg_queue.push (new_msg);
|
}
|
|
XCamReturn
|
DeviceManager::message_loop ()
|
{
|
const static int32_t msg_time_out = -1; //wait until wakeup
|
SmartPtr<XCamMessage> msg = _msg_queue.pop (msg_time_out);
|
if (!msg.ptr ())
|
return XCAM_RETURN_ERROR_THREAD;
|
handle_message (msg);
|
return XCAM_RETURN_NO_ERROR;
|
}
|
|
};
|