blob: 4335e71c1a2541bbef74eeacd4d7471581fd226b [file] [log] [blame]
/*
* cl_image_360_stitch.cpp - CL Image 360 stitch
*
* Copyright (c) 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: Wind Yuan <[email protected]>
*/
#include "cl_image_360_stitch.h"
#define XCAM_BLENDER_GLOBAL_SCALE_EXT_WIDTH 64
#define STITCH_CHECK(ret, msg, ...) \
if ((ret) != XCAM_RETURN_NO_ERROR) { \
XCAM_LOG_WARNING (msg, ## __VA_ARGS__); \
return ret; \
}
namespace XCam {
CLBlenderGlobalScaleKernel::CLBlenderGlobalScaleKernel (
const SmartPtr<CLContext> &context, SmartPtr<CLImage360Stitch> &stitch, bool is_uv)
: CLBlenderScaleKernel (context, is_uv)
, _stitch (stitch)
{
}
SmartPtr<CLImage>
CLBlenderGlobalScaleKernel::get_input_image () {
SmartPtr<CLContext> context = get_context ();
SmartPtr<DrmBoBuffer> input = _stitch->get_global_scale_input ();
CLImageDesc cl_desc;
SmartPtr<CLImage> cl_image;
const VideoBufferInfo &buf_info = input->get_video_info ();
cl_desc.format.image_channel_data_type = CL_UNORM_INT8;
if (_is_uv) {
cl_desc.format.image_channel_order = CL_RG;
cl_desc.width = buf_info.width / 2;
cl_desc.height = buf_info.height / 2;
cl_desc.row_pitch = buf_info.strides[1];
cl_image = new CLVaImage (context, input, cl_desc, buf_info.offsets[1]);
} else {
cl_desc.format.image_channel_order = CL_R;
cl_desc.width = buf_info.width;
cl_desc.height = buf_info.height;
cl_desc.row_pitch = buf_info.strides[0];
cl_image = new CLVaImage (context, input, cl_desc, buf_info.offsets[0]);
}
return cl_image;
}
SmartPtr<CLImage>
CLBlenderGlobalScaleKernel::get_output_image () {
SmartPtr<CLContext> context = get_context ();
SmartPtr<DrmBoBuffer> output = _stitch->get_global_scale_output ();
CLImageDesc cl_desc;
SmartPtr<CLImage> cl_image;
const VideoBufferInfo &buf_info = output->get_video_info ();
cl_desc.format.image_channel_data_type = CL_UNSIGNED_INT16;
cl_desc.format.image_channel_order = CL_RGBA;
if (_is_uv) {
cl_desc.width = buf_info.width / 8;
cl_desc.height = buf_info.height / 2;
cl_desc.row_pitch = buf_info.strides[1];
cl_image = new CLVaImage (context, output, cl_desc, buf_info.offsets[1]);
} else {
cl_desc.width = buf_info.width / 8;
cl_desc.height = buf_info.height;
cl_desc.row_pitch = buf_info.strides[0];
cl_image = new CLVaImage (context, output, cl_desc, buf_info.offsets[0]);
}
return cl_image;
}
bool
CLBlenderGlobalScaleKernel::get_output_info (
uint32_t &out_width, uint32_t &out_height, int &out_offset_x)
{
SmartPtr<DrmBoBuffer> output = _stitch->get_global_scale_output ();
const VideoBufferInfo &output_info = output->get_video_info ();
out_width = output_info.width / 8;
out_height = _is_uv ? output_info.height / 2 : output_info.height;
out_offset_x = 0;
return true;
}
#if HAVE_OPENCV
static CVFMConfig
get_fm_default_config (CLStitchResMode res_mode)
{
CVFMConfig config;
switch (res_mode) {
case CLStitchRes1080P: {
config.sitch_min_width = 56;
config.min_corners = 8;
config.offset_factor = 0.8f;
config.delta_mean_offset = 5.0f;
config.max_adjusted_offset = 12.0f;
break;
}
case CLStitchRes4K: {
config.sitch_min_width = 160;
config.min_corners = 8;
config.offset_factor = 0.8f;
config.delta_mean_offset = 5.0f;
config.max_adjusted_offset = 12.0f;
break;
}
default:
XCAM_LOG_DEBUG ("unknown reslution mode (%d)", res_mode);
break;
}
return config;
}
#endif
static CLStitchInfo
get_default_stitch_info (CLStitchResMode res_mode)
{
CLStitchInfo stitch_info;
switch (res_mode) {
case CLStitchRes1080P: {
stitch_info.merge_width[0] = 56;
stitch_info.merge_width[1] = 56;
stitch_info.crop[0].left = 96;
stitch_info.crop[0].right = 96;
stitch_info.crop[0].top = 0;
stitch_info.crop[0].bottom = 0;
stitch_info.crop[1].left = 96;
stitch_info.crop[1].right = 96;
stitch_info.crop[1].top = 0;
stitch_info.crop[1].bottom = 0;
stitch_info.fisheye_info[0].center_x = 480.0f;
stitch_info.fisheye_info[0].center_y = 480.0f;
stitch_info.fisheye_info[0].wide_angle = 202.8f;
stitch_info.fisheye_info[0].radius = 480.0f;
stitch_info.fisheye_info[0].rotate_angle = -90.0f;
stitch_info.fisheye_info[1].center_x = 1440.0f;
stitch_info.fisheye_info[1].center_y = 480.0f;
stitch_info.fisheye_info[1].wide_angle = 202.8f;
stitch_info.fisheye_info[1].radius = 480.0f;
stitch_info.fisheye_info[1].rotate_angle = 89.4f;
break;
}
case CLStitchRes4K: {
stitch_info.merge_width[0] = 160;
stitch_info.merge_width[1] = 160;
stitch_info.crop[0].left = 64;
stitch_info.crop[0].right = 64;
stitch_info.crop[0].top = 0;
stitch_info.crop[0].bottom = 0;
stitch_info.crop[1].left = 64;
stitch_info.crop[1].right = 64;
stitch_info.crop[1].top = 0;
stitch_info.crop[1].bottom = 0;
stitch_info.fisheye_info[0].center_x = 1024.0f;
stitch_info.fisheye_info[0].center_y = 1024.0f;
stitch_info.fisheye_info[0].wide_angle = 195.0f;
stitch_info.fisheye_info[0].radius = 1040.0f;
stitch_info.fisheye_info[0].rotate_angle = 0.0f;
stitch_info.fisheye_info[1].center_x = 3072.0f;
stitch_info.fisheye_info[1].center_y = 1016.0f;
stitch_info.fisheye_info[1].wide_angle = 192.0f;
stitch_info.fisheye_info[1].radius = 1040.0f;
stitch_info.fisheye_info[1].rotate_angle = 0.4f;
break;
}
default:
XCAM_LOG_DEBUG ("unknown reslution mode (%d)", res_mode);
break;
}
return stitch_info;
}
CLImage360Stitch::CLImage360Stitch (
const SmartPtr<CLContext> &context, CLBlenderScaleMode scale_mode, CLStitchResMode res_mode)
: CLMultiImageHandler (context, "CLImage360Stitch")
, _context (context)
, _output_width (0)
, _output_height (0)
, _scale_mode (scale_mode)
, _res_mode (res_mode)
, _is_stitch_inited (false)
{
#if HAVE_OPENCV
_feature_match = new CVFeatureMatch (context);
XCAM_ASSERT (_feature_match.ptr ());
_feature_match->set_config (get_fm_default_config (res_mode));
#endif
}
bool
CLImage360Stitch::set_stitch_info (CLStitchInfo stitch_info)
{
if (_is_stitch_inited) {
XCAM_LOG_WARNING ("stitching info was initialized and can't be set twice");
return false;
}
for (int index = 0; index < ImageIdxCount; ++index) {
_fisheye[index].handler->set_fisheye_info (stitch_info.fisheye_info[index]);
}
_stitch_info = stitch_info;
_is_stitch_inited = true;
return true;
}
CLStitchInfo
CLImage360Stitch::get_stitch_info ()
{
if (!_is_stitch_inited) {
XCAM_LOG_WARNING ("stitch-info was not initialized, return default parameters");
return get_default_stitch_info (_res_mode);
}
return _stitch_info;
}
bool
CLImage360Stitch::set_fisheye_handler (SmartPtr<CLFisheyeHandler> fisheye, int index)
{
XCAM_ASSERT (index < ImageIdxCount);
_fisheye[index].handler = fisheye;
SmartPtr<CLImageHandler> handler = fisheye;
return add_image_handler (handler);
}
bool
CLImage360Stitch::set_left_blender (SmartPtr<CLBlender> blender)
{
_left_blender = blender;
SmartPtr<CLImageHandler> handler = blender;
return add_image_handler (handler);
}
bool
CLImage360Stitch::set_right_blender (SmartPtr<CLBlender> blender)
{
_right_blender = blender;
SmartPtr<CLImageHandler> handler = blender;
return add_image_handler (handler);
}
bool
CLImage360Stitch::set_image_overlap (const int idx, const Rect &overlap0, const Rect &overlap1)
{
XCAM_ASSERT (idx < ImageIdxCount);
_overlaps[idx][0] = overlap0;
_overlaps[idx][1] = overlap1;
return true;
}
void
CLImage360Stitch::set_feature_match_ocl (bool fm_ocl)
{
#if HAVE_OPENCV
_feature_match->set_ocl (fm_ocl);
#else
XCAM_UNUSED (fm_ocl);
XCAM_LOG_WARNING ("non-OpenCV mode, failed to set ocl for feature match");
#endif
}
#if HAVE_OPENCV
void
CLImage360Stitch::set_feature_match_config (CVFMConfig config)
{
_feature_match->set_config (config);
}
CVFMConfig
CLImage360Stitch::get_feature_match_config ()
{
return _feature_match->get_config ();
}
#endif
void
CLImage360Stitch::calc_fisheye_initial_info (SmartPtr<DrmBoBuffer> &output)
{
const VideoBufferInfo &out_info = output->get_video_info ();
_fisheye[0].width = (out_info.width + _stitch_info.merge_width[0] + _stitch_info.merge_width[1]
+ _stitch_info.crop[0].left + _stitch_info.crop[0].right
+ _stitch_info.crop[1].left + _stitch_info.crop[1].right) / 2;
_fisheye[0].width = XCAM_ALIGN_UP (_fisheye[0].width, 16);
_fisheye[0].height = out_info.height + _stitch_info.crop[0].top + _stitch_info.crop[0].bottom;
XCAM_LOG_INFO (
"fisheye correction output size width:%d height:%d",
_fisheye[0].width, _fisheye[0].height);
_fisheye[1].width = _fisheye[0].width;
_fisheye[1].height = _fisheye[0].height;
float max_dst_angle = 180.0f * _fisheye[0].width / _fisheye[0].height;
for (int index = 0; index < ImageIdxCount; ++index) {
_fisheye[index].handler->set_dst_range (max_dst_angle, 180.0f);
_fisheye[index].handler->set_output_size (_fisheye[index].width, _fisheye[index].height);
}
}
void
CLImage360Stitch::update_image_overlap ()
{
static bool is_merge_info_inited = false;
if (!is_merge_info_inited) {
_img_merge_info[0].left.pos_x = _stitch_info.crop[0].left;
_img_merge_info[0].left.pos_y = _stitch_info.crop[0].top;
_img_merge_info[0].left.width = _stitch_info.merge_width[0];
_img_merge_info[0].left.height = _fisheye[0].height - _stitch_info.crop[0].top - _stitch_info.crop[0].bottom;
_img_merge_info[0].right.pos_x = _fisheye[0].width - _stitch_info.crop[0].right - _stitch_info.merge_width[1];
_img_merge_info[0].right.pos_y = _stitch_info.crop[0].top;
_img_merge_info[0].right.width = _stitch_info.merge_width[1];
_img_merge_info[0].right.height = _fisheye[0].height - _stitch_info.crop[0].top - _stitch_info.crop[0].bottom;
_img_merge_info[1].left.pos_x = _stitch_info.crop[1].left;
_img_merge_info[1].left.pos_y = _stitch_info.crop[1].top;
_img_merge_info[1].left.width = _stitch_info.merge_width[1];
_img_merge_info[1].left.height = _fisheye[1].height - _stitch_info.crop[1].top - _stitch_info.crop[1].bottom;
_img_merge_info[1].right.pos_x = _fisheye[1].width - _stitch_info.crop[1].right - _stitch_info.merge_width[0];
_img_merge_info[1].right.pos_y = _stitch_info.crop[1].top;
_img_merge_info[1].right.width = _stitch_info.merge_width[0];
_img_merge_info[1].right.height = _fisheye[0].height - _stitch_info.crop[1].top - _stitch_info.crop[1].bottom;
is_merge_info_inited = true;
}
set_image_overlap (0, _img_merge_info[0].left, _img_merge_info[0].right);
set_image_overlap (1, _img_merge_info[1].left, _img_merge_info[1].right);
}
XCamReturn
CLImage360Stitch::prepare_buffer_pool_video_info (
const VideoBufferInfo &input, VideoBufferInfo &output)
{
if (_output_width == 0 || _output_height == 0) {
_output_width = input.width;
_output_height = XCAM_ALIGN_UP (input.width / 2, 16);
}
XCAM_FAIL_RETURN(
WARNING,
_output_width && _output_height && (_output_width == _output_height * 2),
XCAM_RETURN_ERROR_PARAM,
"CLImage360Stitch(%s) prepare buffer pool info failed since width:%d height:%d was not set correctly",
XCAM_STR(get_name()), _output_width, _output_height);
// aligned at least XCAM_BLENDER_ALIGNED_WIDTH
uint32_t aligned_width = XCAM_MAX (16, XCAM_BLENDER_ALIGNED_WIDTH);
output.init (
input.format, _output_width, _output_height,
XCAM_ALIGN_UP(_output_width, aligned_width), XCAM_ALIGN_UP(_output_height, 16));
return XCAM_RETURN_NO_ERROR;
}
XCamReturn
CLImage360Stitch::ensure_fisheye_parameters (
SmartPtr<DrmBoBuffer> &input, SmartPtr<DrmBoBuffer> &output)
{
static bool is_fisheye_inited = false;
XCamReturn ret = XCAM_RETURN_NO_ERROR;
if (!is_fisheye_inited) {
calc_fisheye_initial_info (output);
is_fisheye_inited = true;
}
if (!_fisheye[0].pool.ptr ())
create_buffer_pool (_fisheye[0].pool, _fisheye[0].width, _fisheye[0].height);
if (!_fisheye[1].pool.ptr ())
create_buffer_pool (_fisheye[1].pool, _fisheye[1].width, _fisheye[1].height);
_fisheye[0].buf = _fisheye[0].pool->get_buffer (_fisheye[0].pool).dynamic_cast_ptr<DrmBoBuffer> ();
_fisheye[1].buf = _fisheye[1].pool->get_buffer (_fisheye[1].pool).dynamic_cast_ptr<DrmBoBuffer> ();
XCAM_ASSERT (_fisheye[0].buf.ptr () && _fisheye[1].buf.ptr ());
ret = ensure_handler_parameters (_fisheye[0].handler, input, _fisheye[0].buf);
STITCH_CHECK (ret, "execute first fisheye prepare_parameters failed");
ret = ensure_handler_parameters (_fisheye[1].handler, input, _fisheye[1].buf);
STITCH_CHECK (ret, "execute second fisheye prepare_parameters failed");
return XCAM_RETURN_NO_ERROR;
}
XCamReturn
CLImage360Stitch::prepare_global_scale_blender_parameters (
SmartPtr<DrmBoBuffer> &input0, SmartPtr<DrmBoBuffer> &input1, SmartPtr<DrmBoBuffer> &output)
{
XCamReturn ret = XCAM_RETURN_NO_ERROR;
const VideoBufferInfo &in0_info = input0->get_video_info ();
const VideoBufferInfo &in1_info = input1->get_video_info ();
const VideoBufferInfo &out_info = output->get_video_info ();
XCAM_ASSERT (in0_info.height == in1_info.height);
XCAM_ASSERT (in0_info.width <= out_info.width && in1_info.width <= out_info.width);
Rect main_left = get_image_overlap (ImageIdxMain, 0);
Rect main_right = get_image_overlap (ImageIdxMain, 1);
Rect scnd_left = get_image_overlap (ImageIdxSecondary, 1);
Rect scnd_right = get_image_overlap (ImageIdxSecondary, 0);
int main_mid = XCAM_ALIGN_DOWN (in0_info.width / 2, XCAM_BLENDER_ALIGNED_WIDTH);
int scnd_mid = 0;
int out_mid = XCAM_ALIGN_DOWN (out_info.width / 2, XCAM_BLENDER_ALIGNED_WIDTH);
Rect area, out_merge_window;
area.pos_y = out_merge_window.pos_y = 0;
area.height = out_merge_window.pos_y = out_info.height;
//calculate left stitching area(input)
int32_t prev_pos = main_left.pos_x;
main_left.pos_x = XCAM_ALIGN_AROUND (main_left.pos_x, XCAM_BLENDER_ALIGNED_WIDTH);
main_left.width = XCAM_ALIGN_UP (main_left.width, XCAM_BLENDER_ALIGNED_WIDTH);
scnd_left.pos_x += main_left.pos_x - prev_pos;
scnd_left.pos_x = XCAM_ALIGN_AROUND (scnd_left.pos_x, XCAM_BLENDER_ALIGNED_WIDTH);
scnd_left.width = main_left.width;
//calculate right stitching area(input)
prev_pos = main_right.pos_x;
main_right.pos_x = XCAM_ALIGN_AROUND (main_right.pos_x, XCAM_BLENDER_ALIGNED_WIDTH);
main_right.width = XCAM_ALIGN_UP (main_right.width, XCAM_BLENDER_ALIGNED_WIDTH);
scnd_right.pos_x += main_right.pos_x - prev_pos;
scnd_right.pos_x = XCAM_ALIGN_AROUND (scnd_right.pos_x, XCAM_BLENDER_ALIGNED_WIDTH);
scnd_right.width = main_right.width;
//find scnd_mid
scnd_mid = scnd_left.pos_x + (main_mid - main_left.pos_x) - out_mid;
if (scnd_mid < scnd_right.pos_x + scnd_right.width)
scnd_mid = scnd_right.pos_x + scnd_right.width;
// set left blender
area.pos_x = scnd_mid;
area.width = scnd_left.pos_x + scnd_left.width - scnd_mid;
_left_blender->set_input_valid_area (area, 0);
area.pos_x = main_left.pos_x;
area.width = main_mid - main_left.pos_x;
_left_blender->set_input_valid_area (area, 1);
out_merge_window.width = main_left.width;
out_merge_window.pos_x = out_mid - (main_mid - main_left.pos_x);
_left_blender->set_merge_window (out_merge_window);
_left_blender->set_input_merge_area (scnd_left, 0);
_left_blender->set_input_merge_area (main_left, 1);
// set right blender
area.pos_x = main_mid;
area.width = main_right.pos_x + main_right.width - main_mid;
_right_blender->set_input_valid_area (area, 0);
area.pos_x = scnd_right.pos_x;
area.width = scnd_mid - scnd_right.pos_x;
_right_blender->set_input_valid_area (area, 1);
out_merge_window.pos_x = out_mid + (main_right.pos_x - main_mid);
out_merge_window.width = main_right.width;
_right_blender->set_merge_window (out_merge_window);
_right_blender->set_input_merge_area (main_right, 0);
_right_blender->set_input_merge_area (scnd_right, 1);
return ret;
}
XCamReturn
CLImage360Stitch::prepare_local_scale_blender_parameters (
SmartPtr<DrmBoBuffer> &input0, SmartPtr<DrmBoBuffer> &input1, SmartPtr<DrmBoBuffer> &output)
{
XCamReturn ret = XCAM_RETURN_NO_ERROR;
const VideoBufferInfo &in0_info = input0->get_video_info ();
const VideoBufferInfo &in1_info = input1->get_video_info ();
const VideoBufferInfo &out_info = output->get_video_info ();
XCAM_ASSERT (in0_info.height == in1_info.height);
XCAM_ASSERT (in0_info.width <= out_info.width && in1_info.width <= out_info.width);
Rect main_left = get_image_overlap (ImageIdxMain, 0);
Rect main_right = get_image_overlap (ImageIdxMain, 1);
Rect scnd_left = get_image_overlap (ImageIdxSecondary, 1);
Rect scnd_right = get_image_overlap (ImageIdxSecondary, 0);
int main_mid = XCAM_ALIGN_DOWN (in0_info.width / 2, XCAM_BLENDER_ALIGNED_WIDTH);
int scnd_mid = XCAM_ALIGN_DOWN (in1_info.width / 2, XCAM_BLENDER_ALIGNED_WIDTH);
int out_mid = XCAM_ALIGN_DOWN (out_info.width / 2, XCAM_BLENDER_ALIGNED_WIDTH);
Rect area, out_merge_window;
area.pos_y = out_merge_window.pos_y = 0;
area.height = out_merge_window.pos_y = out_info.height;
//calculate left stitching area(input)
int32_t prev_pos = main_left.pos_x;
main_left.pos_x = XCAM_ALIGN_AROUND (main_left.pos_x, XCAM_BLENDER_ALIGNED_WIDTH);
main_left.width = XCAM_ALIGN_UP (main_left.width, XCAM_BLENDER_ALIGNED_WIDTH);
scnd_left.pos_x += main_left.pos_x - prev_pos;
scnd_left.pos_x = XCAM_ALIGN_AROUND (scnd_left.pos_x, XCAM_BLENDER_ALIGNED_WIDTH);
scnd_left.width = main_left.width;
//calculate right stitching area(input)
prev_pos = main_right.pos_x;
main_right.pos_x = XCAM_ALIGN_AROUND (main_right.pos_x, XCAM_BLENDER_ALIGNED_WIDTH);
main_right.width = XCAM_ALIGN_UP (main_right.width, XCAM_BLENDER_ALIGNED_WIDTH);
scnd_right.pos_x += main_right.pos_x - prev_pos;
scnd_right.pos_x = XCAM_ALIGN_AROUND (scnd_right.pos_x, XCAM_BLENDER_ALIGNED_WIDTH);
scnd_right.width = main_right.width;
// set left blender
area.pos_x = scnd_mid;
area.width = scnd_left.pos_x + scnd_left.width - scnd_mid;
_left_blender->set_input_valid_area (area, 0);
area.pos_x = main_left.pos_x;
area.width = main_mid - main_left.pos_x;
_left_blender->set_input_valid_area (area, 1);
int delta_width = out_mid - (main_mid - main_left.pos_x) - (scnd_left.pos_x - scnd_mid);
out_merge_window.width = main_left.width + delta_width;
out_merge_window.pos_x = scnd_left.pos_x - scnd_mid;
_left_blender->set_merge_window (out_merge_window);
_left_blender->set_input_merge_area (scnd_left, 0);
_left_blender->set_input_merge_area (main_left, 1);
// set right blender
area.pos_x = main_mid;
area.width = main_right.pos_x + main_right.width - main_mid;
_right_blender->set_input_valid_area (area, 0);
area.pos_x = scnd_right.pos_x;
area.width = scnd_mid - scnd_right.pos_x;
_right_blender->set_input_valid_area (area, 1);
delta_width = out_mid - (scnd_mid - scnd_right.pos_x) - (main_right.pos_x - main_mid);
out_merge_window.width = main_right.width + delta_width;
out_merge_window.pos_x = out_mid + (main_right.pos_x - main_mid);
_right_blender->set_merge_window (out_merge_window);
_right_blender->set_input_merge_area (main_right, 0);
_right_blender->set_input_merge_area (scnd_right, 1);
return ret;
}
bool
CLImage360Stitch::create_buffer_pool (SmartPtr<BufferPool> &buf_pool, uint32_t width, uint32_t height)
{
VideoBufferInfo buf_info;
width = XCAM_ALIGN_UP (width, 16);
buf_info.init (V4L2_PIX_FMT_NV12, width, height,
XCAM_ALIGN_UP (width, 16), XCAM_ALIGN_UP (height, 16));
SmartPtr<DrmDisplay> display = DrmDisplay::instance ();
buf_pool = new DrmBoBufferPool (display);
XCAM_ASSERT (buf_pool.ptr ());
buf_pool->set_video_info (buf_info);
if (!buf_pool->reserve (6)) {
XCAM_LOG_ERROR ("CLImage360Stitch init buffer pool failed");
return false;
}
return true;
}
XCamReturn
CLImage360Stitch::reset_buffer_info (SmartPtr<DrmBoBuffer> &input)
{
VideoBufferInfo reset_info;
const VideoBufferInfo &buf_info = input->get_video_info ();
Rect img0_left = get_image_overlap (ImageIdxMain, 0);
Rect img0_right = get_image_overlap (ImageIdxMain, 1);
Rect img1_left = get_image_overlap (ImageIdxSecondary, 0);
Rect img1_right = get_image_overlap (ImageIdxSecondary, 1);
uint32_t reset_width = img0_right.pos_x - img0_left.pos_x + img1_right.pos_x - img1_left.pos_x;
reset_width = XCAM_ALIGN_UP (reset_width, XCAM_BLENDER_ALIGNED_WIDTH);
reset_info.init (buf_info.format, reset_width, buf_info.height,
buf_info.aligned_width, buf_info.aligned_height);
input->set_video_info (reset_info);
return XCAM_RETURN_NO_ERROR;
}
XCamReturn
CLImage360Stitch::prepare_parameters (SmartPtr<DrmBoBuffer> &input, SmartPtr<DrmBoBuffer> &output)
{
XCamReturn ret = XCAM_RETURN_NO_ERROR;
if (!_is_stitch_inited)
set_stitch_info (get_default_stitch_info (_res_mode));
ret = ensure_fisheye_parameters (input, output);
STITCH_CHECK (ret, "ensure fisheye parameters failed");
_fisheye[0].buf->attach_buffer (_fisheye[1].buf);
update_image_overlap ();
if (_scale_mode == CLBlenderScaleLocal) {
ret = prepare_local_scale_blender_parameters (_fisheye[0].buf, _fisheye[1].buf, output);
STITCH_CHECK (ret, "prepare local scale blender parameters failed");
ret = ensure_handler_parameters (_left_blender, _fisheye[0].buf, output);
STITCH_CHECK (ret, "left blender: execute ensure_parameters failed");
ret = ensure_handler_parameters (_right_blender, _fisheye[0].buf, output);
STITCH_CHECK (ret, "right blender: execute ensure_parameters failed");
} else { //global scale
const VideoBufferInfo &buf_info = output->get_video_info ();
if (!_scale_buf_pool.ptr ())
create_buffer_pool (_scale_buf_pool, buf_info.width + XCAM_BLENDER_GLOBAL_SCALE_EXT_WIDTH, buf_info.height);
SmartPtr<DrmBoBuffer> scale_input =
_scale_buf_pool->get_buffer (_scale_buf_pool).dynamic_cast_ptr<DrmBoBuffer> ();
XCAM_ASSERT (scale_input.ptr ());
ret = prepare_global_scale_blender_parameters (_fisheye[0].buf, _fisheye[1].buf, scale_input);
STITCH_CHECK (ret, "prepare global scale blender parameters failed");
ret = ensure_handler_parameters (_left_blender, _fisheye[0].buf, scale_input);
STITCH_CHECK (ret, "left blender: execute ensure_parameters failed");
ret = ensure_handler_parameters (_right_blender, _fisheye[0].buf, scale_input);
STITCH_CHECK (ret, "right blender: execute ensure_parameters failed");
reset_buffer_info (scale_input);
_scale_global_input = scale_input;
_scale_global_output = output;
}
return XCAM_RETURN_NO_ERROR;
}
XCamReturn
CLImage360Stitch::execute_done (SmartPtr<DrmBoBuffer> &output)
{
#if HAVE_OPENCV
if (!_feature_match->is_ocl_path ())
get_context ()->finish ();
#endif
_scale_global_input.release ();
_scale_global_output.release ();
return CLMultiImageHandler::execute_done (output);
}
#if HAVE_OPENCV
static void
convert_to_cv_rect (ImageMergeInfo merge_info, cv::Rect &crop_left, cv::Rect &crop_right)
{
crop_left.x = merge_info.left.pos_x;
crop_left.y = merge_info.left.pos_y + merge_info.left.height / 3;
crop_left.width = merge_info.left.width;
crop_left.height = merge_info.left.height / 3;
crop_right.x = merge_info.right.pos_x;
crop_right.y = merge_info.right.pos_y + merge_info.right.height / 3;
crop_right.width = merge_info.right.width;
crop_right.height = merge_info.right.height / 3;
}
static void
convert_to_xcam_rect (cv::Rect crop_left, cv::Rect crop_right, ImageMergeInfo &merge_info)
{
merge_info.left.pos_x = crop_left.x;
merge_info.left.width = crop_left.width;
merge_info.right.pos_x = crop_right.x;
merge_info.right.width = crop_right.width;
}
#endif
XCamReturn
CLImage360Stitch::sub_handler_execute_done (SmartPtr<CLImageHandler> &handler)
{
#if HAVE_OPENCV
XCAM_ASSERT (handler.ptr ());
if (handler.ptr () == _fisheye[ImageIdxCount - 1].handler.ptr ()) {
cv::Rect img0_crop_left, img0_crop_right, img1_crop_left, img1_crop_right;
convert_to_cv_rect (_img_merge_info[0], img0_crop_left, img0_crop_right);
convert_to_cv_rect (_img_merge_info[1], img1_crop_left, img1_crop_right);
get_context ()->finish ();
_feature_match->optical_flow_feature_match (
_fisheye[0].width, _fisheye[0].buf, _fisheye[1].buf,
img0_crop_left, img0_crop_right, img1_crop_left, img1_crop_right);
//update merge info
convert_to_xcam_rect (img0_crop_left, img0_crop_right, _img_merge_info[0]);
convert_to_xcam_rect (img1_crop_left, img1_crop_right, _img_merge_info[1]);
}
#else
XCAM_UNUSED (handler);
#endif
return XCAM_RETURN_NO_ERROR;
}
static SmartPtr<CLImageKernel>
create_blender_global_scale_kernel (
const SmartPtr<CLContext> &context,
SmartPtr<CLImage360Stitch> &stitch,
bool is_uv)
{
char transform_option[1024];
snprintf (transform_option, sizeof(transform_option), "-DPYRAMID_UV=%d", is_uv ? 1 : 0);
static const XCamKernelInfo &kernel_info = {
"kernel_pyramid_scale",
#include "kernel_gauss_lap_pyramid.clx"
, 0
};
SmartPtr<CLImageKernel> kernel;
kernel = new CLBlenderGlobalScaleKernel (context, stitch, is_uv);
XCAM_ASSERT (kernel.ptr ());
XCAM_FAIL_RETURN (
ERROR,
kernel->build_kernel (kernel_info, transform_option) == XCAM_RETURN_NO_ERROR,
NULL,
"load blender global scaling kernel(%s) failed", is_uv ? "UV" : "Y");
return kernel;
}
SmartPtr<CLImageHandler>
create_image_360_stitch (
const SmartPtr<CLContext> &context, bool need_seam,
CLBlenderScaleMode scale_mode, bool fisheye_map, CLStitchResMode res_mode)
{
const int layer = 2;
const bool need_uv = true;
SmartPtr<CLFisheyeHandler> fisheye;
SmartPtr<CLBlender> left_blender, right_blender;
SmartPtr<CLImage360Stitch> stitch = new CLImage360Stitch (context, scale_mode, res_mode);
XCAM_ASSERT (stitch.ptr ());
for (int index = 0; index < ImageIdxCount; ++index) {
fisheye = create_fisheye_handler (context, fisheye_map).dynamic_cast_ptr<CLFisheyeHandler> ();
XCAM_FAIL_RETURN (ERROR, fisheye.ptr (), NULL, "image_360_stitch create fisheye handler failed");
fisheye->disable_buf_pool (true);
stitch->set_fisheye_handler (fisheye, index);
}
left_blender = create_pyramid_blender (context, layer, need_uv, need_seam, scale_mode).dynamic_cast_ptr<CLBlender> ();
XCAM_FAIL_RETURN (ERROR, left_blender.ptr (), NULL, "image_360_stitch create left blender failed");
left_blender->disable_buf_pool (true);
left_blender->swap_input_idx (true);
stitch->set_left_blender (left_blender);
right_blender = create_pyramid_blender (context, layer, need_uv, need_seam, scale_mode).dynamic_cast_ptr<CLBlender> ();
XCAM_FAIL_RETURN (ERROR, right_blender.ptr (), NULL, "image_360_stitch create right blender failed");
right_blender->disable_buf_pool (true);
stitch->set_right_blender (right_blender);
if (scale_mode == CLBlenderScaleGlobal) {
int max_plane = need_uv ? 2 : 1;
bool uv_status[2] = {false, true};
for (int plane = 0; plane < max_plane; ++plane) {
SmartPtr<CLImageKernel> kernel = create_blender_global_scale_kernel (context, stitch, uv_status[plane]);
XCAM_FAIL_RETURN (ERROR, kernel.ptr (), NULL, "create blender global scaling kernel failed");
stitch->add_kernel (kernel);
}
}
return stitch;
}
}