/*
* xcam_plugin_dvs.cpp - Digital Video Stabilizer plugin
*
* Copyright (c) 2014-2016 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_common.h>
#include <base/xcam_smart_description.h>
#include <base/xcam_smart_result.h>
#include <base/xcam_3a_result.h>
#include <base/xcam_buffer.h>
#include <smartptr.h>
#if HAVE_LIBDRM
#include <drm_display.h>
#endif
#include <dma_video_buffer.h>
#include <ocl/cl_utils.h>
#include <ocl/cl_context.h>
#include <ocl/cl_device.h>
#include <ocl/cl_memory.h>
#include <opencv2/core/ocl.hpp>
#include "libdvs/libdvs.h"
#define DVS_MOTION_FILTER_RADIUS 15
struct DvsBuffer : public DvsData
{
XCamVideoBuffer* buffer;
DvsBuffer () { }
DvsBuffer (XCamVideoBuffer* buf, cv::UMat& frame)
: buffer (buf)
{
buffer->ref(buffer);
data = frame;
}
~DvsBuffer () {
buffer->unref(buffer);
}
};
XCamReturn dvs_create_context(XCamSmartAnalysisContext **context, uint32_t *async_mode, XcamPostResultsFunc post_func)
{
XCAM_UNUSED (async_mode);
XCAM_UNUSED (post_func);
DvsInterface* theDVS = NULL;
theDVS = getDigitalVideoStabilizer();
if (theDVS == NULL) {
return XCAM_RETURN_ERROR_MEM;
}
theDVS->init(640, 480, false);
*context = (XCamSmartAnalysisContext *)theDVS;
cl_platform_id platform_id = XCam::CLDevice::instance()->get_platform_id();
char* platform_name = XCam::CLDevice::instance()->get_platform_name ();
cl_device_id device_id = XCam::CLDevice::instance()->get_device_id();
cl_context cl_context_id = XCam::CLDevice::instance()->get_context()->get_context_id();
clRetainContext (cl_context_id);
cv::ocl::attachContext (platform_name, platform_id, cl_context_id, device_id);
return XCAM_RETURN_NO_ERROR;
}
XCamReturn dvs_destroy_context(XCamSmartAnalysisContext *context)
{
DvsInterface *theDVS = (DvsInterface *)context;
theDVS->release ();
delete (theDVS);
return XCAM_RETURN_NO_ERROR;
}
XCamReturn dvs_update_params(XCamSmartAnalysisContext *context, const XCamSmartAnalysisParam *params)
{
XCAM_UNUSED (context);
XCAM_UNUSED (params);
return XCAM_RETURN_NO_ERROR;
}
XCamReturn dvs_analyze(XCamSmartAnalysisContext *context, XCamVideoBuffer *buffer, XCam3aResultHead *results[], uint32_t *res_count)
{
DvsInterface *theDVS = (DvsInterface *)context;
DvsResult dvsResult;
if (buffer->info.format != V4L2_PIX_FMT_NV12 || buffer->mem_type != XCAM_MEM_TYPE_PRIVATE_BO)
return XCAM_RETURN_ERROR_PARAM;
int buffer_fd = xcam_video_buffer_get_fd(buffer);
XCam::VideoBufferInfo buffer_info;
buffer_info.init (buffer->info.format, buffer->info.width, buffer->info.height,
buffer->info.aligned_width, buffer->info.aligned_height, buffer->info.size);
XCam::SmartPtr<XCam::VideoBuffer> new_buffer = new XCam::DmaVideoBuffer(buffer_info, buffer_fd);
XCam::SmartPtr<XCam::VideoBuffer> video_buffer;
#if HAVE_LIBDRM
XCam::SmartPtr<XCam::DrmDisplay> display = XCam::DrmDisplay::instance ();
video_buffer = display->convert_to_drm_bo_buf (display, new_buffer);
#else
video_buffer = new_buffer;
#endif
XCam::SmartPtr<XCam::CLContext> cl_Context = XCam::CLDevice::instance()->get_context();
XCam::SmartPtr<XCam::CLBuffer> cl_buffer = XCam::convert_to_clbuffer (cl_Context, video_buffer);
cl_mem cl_mem_id = cl_buffer->get_mem_id();
clRetainMemObject(cl_mem_id);
cv::UMat frame;
cv::ocl::convertFromBuffer(cl_mem_id, buffer->info.strides[0], buffer->info.height, buffer->info.width, CV_8U, frame);
DvsBuffer* dvs_buf = new DvsBuffer(buffer, frame);
//set default config
DvsConfig config;
memset(&config, 0, sizeof(DvsConfig));
config.use_ocl = true;
config.frame_width = buffer->info.width;
config.frame_height = buffer->info.height;
config.radius = DVS_MOTION_FILTER_RADIUS;
config.stdev = 10.0f;
config.features = 1000;
config.minDistance = 20.0f;
theDVS->setConfig(&config);
theDVS->nextStabilizedMotion(dvs_buf, &dvsResult);
delete(dvs_buf);
if ((dvsResult.frame_id < 0) && (dvsResult.valid == false))
{
results[0] = NULL;
*res_count = 0;
XCAM_LOG_WARNING ("dvs_analyze not ready! ");
} else {
XCamDVSResult *dvs_result = (XCamDVSResult *)malloc(sizeof(XCamDVSResult));
memset(dvs_result, 0, sizeof(XCamDVSResult));
dvs_result->head.type = XCAM_3A_RESULT_DVS;
dvs_result->head.process_type = XCAM_IMAGE_PROCESS_POST;
dvs_result->head.version = 0x080;
dvs_result->frame_id = dvsResult.frame_id;
dvs_result->frame_width = dvsResult.frame_width;
dvs_result->frame_height = dvsResult.frame_height;
memcpy(dvs_result->proj_mat, dvsResult.proj_mat, sizeof(DvsResult::proj_mat));
results[0] = (XCam3aResultHead *)dvs_result;
*res_count = 1;
}
return XCAM_RETURN_NO_ERROR;
}
void dvs_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 (results[i]);
}
}
}
XCAM_BEGIN_DECLARE
XCamSmartAnalysisDescription xcam_smart_analysis_desciption =
{
0x080,
sizeof (XCamSmartAnalysisDescription),
10,
"digital_video_stabilizer",
dvs_create_context,
dvs_destroy_context,
dvs_update_params,
dvs_analyze,
dvs_free_results,
};
XCAM_END_DECLARE