Home | History | Annotate | Download | only in soft
      1 /*
      2  * soft_stitcher.cpp - soft stitcher implementation
      3  *
      4  *  Copyright (c) 2017 Intel Corporation
      5  *
      6  * Licensed under the Apache License, Version 2.0 (the "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *      http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  *
     18  * Author: Wind Yuan <feng.yuan (at) intel.com>
     19  */
     20 
     21 #include "soft_stitcher.h"
     22 #include "soft_blender.h"
     23 #include "soft_geo_mapper.h"
     24 #include "soft_video_buf_allocator.h"
     25 #include "interface/feature_match.h"
     26 #include "surview_fisheye_dewarp.h"
     27 #include "soft_copy_task.h"
     28 #include "xcam_utils.h"
     29 #include <map>
     30 
     31 #define ENABLE_FEATURE_MATCH HAVE_OPENCV
     32 
     33 #if ENABLE_FEATURE_MATCH
     34 #include "cv_capi_feature_match.h"
     35 #ifndef ANDROID
     36 #include <opencv2/core/ocl.hpp>
     37 #endif
     38 #endif
     39 
     40 #define SOFT_STITCHER_ALIGNMENT_X 8
     41 #define SOFT_STITCHER_ALIGNMENT_Y 4
     42 
     43 #define MAP_FACTOR_X  16
     44 #define MAP_FACTOR_Y  16
     45 
     46 #define DUMP_STITCHER 0
     47 
     48 namespace XCam {
     49 
     50 #if DUMP_STITCHER
     51 static void
     52 stitcher_dump_buf (const SmartPtr<VideoBuffer> buf, uint32_t idx, const char *prefix)
     53 {
     54     XCAM_ASSERT (prefix);
     55     char name[256];
     56     snprintf (name, 256, "%s-%d", prefix, idx);
     57     dump_buf_perfix_path (buf, name);
     58 }
     59 #else
     60 static void stitcher_dump_buf (const SmartPtr<VideoBuffer> buf, ...) {
     61     XCAM_UNUSED (buf);
     62 }
     63 #endif
     64 
     65 
     66 namespace SoftSitcherPriv {
     67 
     68 DECLARE_HANDLER_CALLBACK (CbGeoMap, SoftStitcher, dewarp_done);
     69 DECLARE_HANDLER_CALLBACK (CbBlender, SoftStitcher, blender_done);
     70 DECLARE_WORK_CALLBACK (CbCopyTask, SoftStitcher, copy_task_done);
     71 
     72 struct BlenderParam
     73     : SoftBlender::BlenderParam
     74 {
     75     SmartPtr<SoftStitcher::StitcherParam>  stitch_param;
     76     uint32_t idx;
     77 
     78     BlenderParam (
     79         uint32_t i,
     80         const SmartPtr<VideoBuffer> &in0,
     81         const SmartPtr<VideoBuffer> &in1,
     82         const SmartPtr<VideoBuffer> &out)
     83         : SoftBlender::BlenderParam (in0, in1, out)
     84         , idx (i)
     85     {}
     86 };
     87 
     88 typedef std::map<void*, SmartPtr<BlenderParam>> BlenderParams;
     89 typedef std::map<void*, int32_t> BlendCopyTaskNums;
     90 
     91 struct HandlerParam
     92     : ImageHandler::Parameters
     93 {
     94     SmartPtr<SoftStitcher::StitcherParam>  stitch_param;
     95     uint32_t idx;
     96 
     97     HandlerParam (uint32_t i)
     98         : idx (i)
     99     {}
    100 };
    101 
    102 struct StitcherCopyArgs
    103     : XCamSoftTasks::CopyTask::Args
    104 {
    105     uint32_t idx;
    106 
    107     StitcherCopyArgs (
    108         uint32_t i,
    109         const SmartPtr<ImageHandler::Parameters> &param)
    110         : XCamSoftTasks::CopyTask::Args (param)
    111         , idx (i)
    112     {}
    113 };
    114 
    115 struct Factor {
    116     float x, y;
    117 
    118     Factor () : x (1.0f), y (1.0f) {}
    119     void reset () {
    120         x = 1.0f;
    121         y = 1.0f;
    122     }
    123 };
    124 
    125 struct Overlap {
    126     SmartPtr<FeatureMatch>       matcher;
    127     SmartPtr<SoftBlender>        blender;
    128     BlenderParams                param_map;
    129 
    130     SmartPtr<BlenderParam> find_blender_param_in_map (
    131         const SmartPtr<SoftStitcher::StitcherParam> &key,
    132         const uint32_t idx);
    133 };
    134 
    135 struct FisheyeDewarp {
    136     SmartPtr<SoftGeoMapper>      dewarp;
    137     SmartPtr<BufferPool>         buf_pool;
    138     Factor                       left_match_factor, right_match_factor;
    139 
    140     bool set_dewarp_factor ();
    141     XCamReturn set_dewarp_geo_table (
    142         SmartPtr<SoftGeoMapper> mapper,
    143         const CameraInfo &cam_info,
    144         const Stitcher::RoundViewSlice &view_slice,
    145         const BowlDataConfig &bowl);
    146 };
    147 
    148 struct Copier {
    149     SmartPtr<XCamSoftTasks::CopyTask>    copy_task;
    150     Stitcher::CopyArea                   copy_area;
    151 
    152     XCamReturn start_copy_task (
    153         const SmartPtr<ImageHandler::Parameters> &param,
    154         const uint32_t idx, const SmartPtr<VideoBuffer> &buf);
    155 };
    156 typedef std::vector<Copier>    Copiers;
    157 
    158 class StitcherImpl {
    159     friend class XCam::SoftStitcher;
    160 
    161 public:
    162     StitcherImpl (SoftStitcher *handler)
    163         : _stitcher (handler)
    164     {}
    165 
    166     XCamReturn init_config (uint32_t count);
    167 
    168     bool remove_task_count (const SmartPtr<SoftStitcher::StitcherParam> &param);
    169     int32_t dec_task_count (const SmartPtr<SoftStitcher::StitcherParam> &param);
    170 
    171     XCamReturn start_dewarp_works (const SmartPtr<SoftStitcher::StitcherParam> &param);
    172     XCamReturn start_task_count (const SmartPtr<SoftStitcher::StitcherParam> &param);
    173     XCamReturn start_overlap_tasks (
    174         const SmartPtr<SoftStitcher::StitcherParam> &param,
    175         const uint32_t idx, const SmartPtr<VideoBuffer> &buf);
    176     XCamReturn start_copy_tasks (
    177         const SmartPtr<SoftStitcher::StitcherParam> &param,
    178         const uint32_t idx, const SmartPtr<VideoBuffer> &buf);
    179 
    180     XCamReturn start_single_blender (const uint32_t idx, const SmartPtr<BlenderParam> &param);
    181     XCamReturn stop ();
    182 
    183     XCamReturn fisheye_dewarp_to_table ();
    184     XCamReturn feature_match (
    185         const SmartPtr<VideoBuffer> &left_buf,
    186         const SmartPtr<VideoBuffer> &right_buf,
    187         const uint32_t idx);
    188 
    189     bool get_and_reset_feature_match_factors (uint32_t idx, Factor &left, Factor &right);
    190 
    191 private:
    192     XCamReturn init_fisheye (uint32_t idx);
    193     bool init_dewarp_factors (uint32_t idx);
    194     XCamReturn create_copier (Stitcher::CopyArea area);
    195 
    196 private:
    197     FisheyeDewarp           _fisheye [XCAM_STITCH_MAX_CAMERAS];
    198     Overlap                 _overlaps [XCAM_STITCH_MAX_CAMERAS];
    199     Copiers                 _copiers;
    200     SmartPtr<BufferPool>    _dewarp_pool;
    201 
    202     Mutex                   _map_mutex;
    203     BlendCopyTaskNums       _task_counts;
    204 
    205     SoftStitcher           *_stitcher;
    206 };
    207 
    208 bool
    209 StitcherImpl::init_dewarp_factors (uint32_t idx)
    210 {
    211     XCAM_FAIL_RETURN (
    212         ERROR, _fisheye[idx].dewarp.ptr (), false,
    213         "FisheyeDewarp dewarp handler empty");
    214 
    215     Factor match_left_factor, match_right_factor;
    216     get_and_reset_feature_match_factors (idx, match_left_factor, match_right_factor);
    217 
    218     Factor unify_factor, last_left_factor, last_right_factor;
    219     _fisheye[idx].dewarp->get_factors (unify_factor.x, unify_factor.y);
    220     last_left_factor = last_right_factor = unify_factor;
    221     if (XCAM_DOUBLE_EQUAL_AROUND (unify_factor.x, 0.0f) ||
    222             XCAM_DOUBLE_EQUAL_AROUND (unify_factor.y, 0.0f)) { // not started.
    223         return true;
    224     }
    225 
    226     Factor cur_left, cur_right;
    227     cur_left.x = last_left_factor.x * match_left_factor.x;
    228     cur_left.y = last_left_factor.y * match_left_factor.y;
    229     cur_right.x = last_right_factor.x * match_right_factor.x;
    230     cur_right.y = last_right_factor.y * match_right_factor.y;
    231 
    232     unify_factor.x = (cur_left.x + cur_right.x) / 2.0f;
    233     unify_factor.y = (cur_left.y + cur_right.y) / 2.0f;
    234     _fisheye[idx].dewarp->set_factors (unify_factor.x, unify_factor.y);
    235 
    236     return true;
    237 }
    238 
    239 XCamReturn
    240 FisheyeDewarp::set_dewarp_geo_table (
    241     SmartPtr<SoftGeoMapper> mapper,
    242     const CameraInfo &cam_info,
    243     const Stitcher::RoundViewSlice &view_slice,
    244     const BowlDataConfig &bowl)
    245 {
    246     PolyFisheyeDewarp fd;
    247     fd.set_intrinsic_param (cam_info.calibration.intrinsic);
    248     fd.set_extrinsic_param (cam_info.calibration.extrinsic);
    249 
    250     uint32_t table_width, table_height;
    251     table_width = view_slice.width / MAP_FACTOR_X;
    252     table_width = XCAM_ALIGN_UP (table_width, 4);
    253     table_height = view_slice.height / MAP_FACTOR_Y;
    254     table_height = XCAM_ALIGN_UP (table_height, 2);
    255     SurViewFisheyeDewarp::MapTable map_table(table_width * table_height);
    256     fd.fisheye_dewarp (
    257         map_table, table_width, table_height,
    258         view_slice.width, view_slice.height, bowl);
    259 
    260     XCAM_FAIL_RETURN (
    261         ERROR, mapper->set_lookup_table (map_table.data (), table_width, table_height),
    262         XCAM_RETURN_ERROR_UNKNOWN, "set fisheye dewarp lookup table failed");
    263     return XCAM_RETURN_NO_ERROR;
    264 }
    265 
    266 bool
    267 StitcherImpl::get_and_reset_feature_match_factors (uint32_t idx, Factor &left, Factor &right)
    268 {
    269     uint32_t cam_num = _stitcher->get_camera_num ();
    270     XCAM_FAIL_RETURN (
    271         ERROR, idx < cam_num, false,
    272         "get dewarp factor failed, idx(%d) > camera_num(%d)", idx, cam_num);
    273 
    274     SmartLock locker (_map_mutex);
    275     left = _fisheye[idx].left_match_factor;
    276     right = _fisheye[idx].right_match_factor;
    277 
    278     _fisheye[idx].left_match_factor.reset ();
    279     _fisheye[idx].right_match_factor.reset ();
    280     return true;
    281 }
    282 
    283 XCamReturn
    284 StitcherImpl::init_fisheye (uint32_t idx)
    285 {
    286     FisheyeDewarp &fisheye = _fisheye[idx];
    287     SmartPtr<ImageHandler::Callback> dewarp_cb = new CbGeoMap (_stitcher);
    288     fisheye.dewarp = new SoftGeoMapper ("sitcher_remapper");
    289     XCAM_ASSERT (fisheye.dewarp.ptr ());
    290     fisheye.dewarp->set_callback (dewarp_cb);
    291 
    292     Stitcher::RoundViewSlice view_slice =
    293         _stitcher->get_round_view_slice (idx);
    294 
    295     VideoBufferInfo buf_info;
    296     buf_info.init (
    297         V4L2_PIX_FMT_NV12, view_slice.width, view_slice.height,
    298         XCAM_ALIGN_UP (view_slice.width, SOFT_STITCHER_ALIGNMENT_X),
    299         XCAM_ALIGN_UP (view_slice.height, SOFT_STITCHER_ALIGNMENT_Y));
    300 
    301     fisheye.buf_pool = new SoftVideoBufAllocator (buf_info);
    302     XCAM_ASSERT (fisheye.buf_pool.ptr ());
    303     XCAM_FAIL_RETURN (
    304         ERROR, fisheye.buf_pool->reserve (2), XCAM_RETURN_ERROR_MEM,
    305         "stitcher:%s reserve dewarp buffer pool(w:%d,h:%d) failed",
    306         XCAM_STR (_stitcher->get_name ()), buf_info.width, buf_info.height);
    307     return XCAM_RETURN_NO_ERROR;
    308 }
    309 
    310 XCamReturn
    311 StitcherImpl::create_copier (Stitcher::CopyArea area)
    312 {
    313     XCAM_FAIL_RETURN (
    314         ERROR,
    315         area.in_idx != INVALID_INDEX &&
    316         area.in_area.width == area.out_area.width && area.in_area.height == area.out_area.height,
    317         XCAM_RETURN_ERROR_PARAM,
    318         "stitcher: copy area (idx:%d) is invalid", area.in_idx);
    319 
    320     SmartPtr<Worker::Callback> copy_cb = new CbCopyTask (_stitcher);
    321     XCAM_ASSERT (copy_cb.ptr ());
    322 
    323     Copier copier;
    324     copier.copy_task = new XCamSoftTasks::CopyTask (copy_cb);
    325     XCAM_ASSERT (copier.copy_task.ptr ());
    326     copier.copy_area = area;
    327     _copiers.push_back (copier);
    328 
    329     return XCAM_RETURN_NO_ERROR;
    330 }
    331 
    332 XCamReturn
    333 StitcherImpl::init_config (uint32_t count)
    334 {
    335     XCamReturn ret = XCAM_RETURN_NO_ERROR;
    336 
    337     SmartPtr<ImageHandler::Callback> blender_cb = new CbBlender (_stitcher);
    338     for (uint32_t i = 0; i < count; ++i) {
    339         ret = init_fisheye (i);
    340         XCAM_FAIL_RETURN (
    341             ERROR, xcam_ret_is_ok (ret), ret,
    342             "stitcher:%s init fisheye failed, idx:%d.", XCAM_STR (_stitcher->get_name ()), i);
    343 
    344 #if ENABLE_FEATURE_MATCH
    345         _overlaps[i].matcher = new CVCapiFeatureMatch;
    346 
    347         CVFMConfig config;
    348         config.sitch_min_width = 136;
    349         config.min_corners = 4;
    350         config.offset_factor = 0.8f;
    351         config.delta_mean_offset = 120.0f;
    352         config.recur_offset_error = 8.0f;
    353         config.max_adjusted_offset = 24.0f;
    354         config.max_valid_offset_y = 20.0f;
    355 #ifndef ANDROID
    356         config.max_track_error = 28.0f;
    357 #else
    358         config.max_track_error = 3600.0f;
    359 #endif
    360         _overlaps[i].matcher->set_config (config);
    361         _overlaps[i].matcher->set_fm_index (i);
    362 #endif
    363 
    364         _overlaps[i].blender = create_soft_blender ().dynamic_cast_ptr<SoftBlender>();
    365         XCAM_ASSERT (_overlaps[i].blender.ptr ());
    366         _overlaps[i].blender->set_callback (blender_cb);
    367         _overlaps[i].param_map.clear ();
    368     }
    369 
    370     Stitcher::CopyAreaArray areas = _stitcher->get_copy_area ();
    371     uint32_t size = areas.size ();
    372     for (uint32_t i = 0; i < size; ++i) {
    373         XCAM_LOG_DEBUG ("soft-stitcher:copy area (idx:%d) input area(%d, %d, %d, %d) output area(%d, %d, %d, %d)",
    374                         areas[i].in_idx,
    375                         areas[i].in_area.pos_x, areas[i].in_area.pos_y, areas[i].in_area.width, areas[i].in_area.height,
    376                         areas[i].out_area.pos_x, areas[i].out_area.pos_y, areas[i].out_area.width, areas[i].out_area.height);
    377 
    378         XCAM_ASSERT (areas[i].in_idx < size);
    379         ret = create_copier (areas[i]);
    380         XCAM_FAIL_RETURN (
    381             ERROR, xcam_ret_is_ok (ret), ret,
    382             "soft-stitcher::%s init copier failed, idx:%d.", XCAM_STR (_stitcher->get_name ()), i);
    383     }
    384 
    385     return XCAM_RETURN_NO_ERROR;
    386 }
    387 
    388 bool
    389 StitcherImpl::remove_task_count (const SmartPtr<SoftStitcher::StitcherParam> &param)
    390 {
    391     XCAM_ASSERT (param.ptr ());
    392     SmartLock locker (_map_mutex);
    393     BlendCopyTaskNums::iterator i = _task_counts.find (param.ptr ());
    394     if (i == _task_counts.end ())
    395         return false;
    396 
    397     _task_counts.erase (i);
    398     return true;
    399 }
    400 
    401 int32_t
    402 StitcherImpl::dec_task_count (const SmartPtr<SoftStitcher::StitcherParam> &param)
    403 {
    404     XCAM_ASSERT (param.ptr ());
    405     SmartLock locker (_map_mutex);
    406     BlendCopyTaskNums::iterator i = _task_counts.find (param.ptr ());
    407     if (i == _task_counts.end ())
    408         return -1;
    409 
    410     int32_t &count = i->second;
    411     --count;
    412     if (count > 0)
    413         return count;
    414 
    415     XCAM_ASSERT (count == 0);
    416     _task_counts.erase (i);
    417     return 0;
    418 }
    419 
    420 XCamReturn
    421 StitcherImpl::fisheye_dewarp_to_table ()
    422 {
    423     uint32_t camera_num = _stitcher->get_camera_num ();
    424     for (uint32_t i = 0; i < camera_num; ++i) {
    425         CameraInfo cam_info;
    426         _stitcher->get_camera_info (i, cam_info);
    427         Stitcher::RoundViewSlice view_slice = _stitcher->get_round_view_slice (i);
    428 
    429         BowlDataConfig bowl = _stitcher->get_bowl_config ();
    430         bowl.angle_start = view_slice.hori_angle_start;
    431         bowl.angle_end = format_angle (view_slice.hori_angle_start + view_slice.hori_angle_range);
    432 
    433         uint32_t out_width, out_height;
    434         _stitcher->get_output_size (out_width, out_height);
    435 
    436         _fisheye[i].dewarp->set_output_size (view_slice.width, view_slice.height);
    437         if (bowl.angle_end < bowl.angle_start)
    438             bowl.angle_start -= 360.0f;
    439         XCAM_LOG_INFO (
    440             "soft-stitcher:%s camera(idx:%d) info (angle start:%.2f, range:%.2f), bowl info (angle start%.2f, end:%.2f)",
    441             XCAM_STR (_stitcher->get_name ()), i,
    442             view_slice.hori_angle_start, view_slice.hori_angle_range,
    443             bowl.angle_start, bowl.angle_end);
    444         XCamReturn ret = _fisheye[i].set_dewarp_geo_table (_fisheye[i].dewarp, cam_info, view_slice, bowl);
    445         XCAM_FAIL_RETURN (
    446             ERROR, xcam_ret_is_ok (ret), ret,
    447             "stitcher:%s set dewarp geo table failed, idx:%d.", XCAM_STR (_stitcher->get_name ()), i);
    448 
    449     }
    450 
    451     return XCAM_RETURN_NO_ERROR;
    452 }
    453 
    454 XCamReturn
    455 StitcherImpl::start_dewarp_works (const SmartPtr<SoftStitcher::StitcherParam> &param)
    456 {
    457     uint32_t camera_num = _stitcher->get_camera_num ();
    458     Factor cur_left, cur_right;
    459 
    460     for (uint32_t i = 0; i < camera_num; ++i) {
    461         SmartPtr<VideoBuffer> out_buf = _fisheye[i].buf_pool->get_buffer ();
    462         SmartPtr<HandlerParam> dewarp_params = new HandlerParam (i);
    463         dewarp_params->in_buf = param->in_bufs[i];
    464         dewarp_params->out_buf = out_buf;
    465         dewarp_params->stitch_param = param;
    466 
    467         init_dewarp_factors (i);
    468         XCamReturn ret = _fisheye[i].dewarp->execute_buffer (dewarp_params, false);
    469         XCAM_FAIL_RETURN (
    470             ERROR, xcam_ret_is_ok (ret), ret,
    471             "soft-stitcher:%s fisheye dewarp buffer failed", XCAM_STR (_stitcher->get_name ()));
    472     }
    473     return XCAM_RETURN_NO_ERROR;
    474 }
    475 
    476 SmartPtr<BlenderParam>
    477 Overlap::find_blender_param_in_map (
    478     const SmartPtr<SoftStitcher::StitcherParam> &key,
    479     const uint32_t idx)
    480 {
    481     SmartPtr<BlenderParam> param;
    482     BlenderParams::iterator i = param_map.find (key.ptr ());
    483     if (i == param_map.end ()) {
    484         param = new BlenderParam (idx, NULL, NULL, NULL);
    485         XCAM_ASSERT (param.ptr ());
    486         param->stitch_param = key;
    487         param_map.insert (std::make_pair ((void*)key.ptr (), param));
    488     } else {
    489         param = (*i).second;
    490     }
    491 
    492     return param;
    493 }
    494 
    495 XCamReturn
    496 StitcherImpl::feature_match (
    497     const SmartPtr<VideoBuffer> &left_buf,
    498     const SmartPtr<VideoBuffer> &right_buf,
    499     const uint32_t idx)
    500 {
    501     const Stitcher::ImageOverlapInfo overlap_info = _stitcher->get_overlap (idx);
    502     Rect left_ovlap = overlap_info.left;
    503     Rect right_ovlap = overlap_info.right;
    504     const VideoBufferInfo left_buf_info = left_buf->get_video_info ();
    505 
    506     left_ovlap.pos_y = left_ovlap.height / 5;
    507     left_ovlap.height = left_ovlap.height / 2;
    508     right_ovlap.pos_y = right_ovlap.height / 5;
    509     right_ovlap.height = right_ovlap.height / 2;
    510 
    511     _overlaps[idx].matcher->reset_offsets ();
    512     _overlaps[idx].matcher->optical_flow_feature_match (
    513         left_buf, right_buf, left_ovlap, right_ovlap, left_buf_info.width);
    514     float left_offsetx = _overlaps[idx].matcher->get_current_left_offset_x ();
    515     Factor left_factor, right_factor;
    516 
    517     uint32_t left_idx = idx;
    518     float center_x = (float) _stitcher->get_center (left_idx).slice_center_x;
    519     float feature_center_x = (float)left_ovlap.pos_x + (left_ovlap.width / 2.0f);
    520     float range = feature_center_x - center_x;
    521     XCAM_ASSERT (range > 1.0f);
    522     right_factor.x = (range + left_offsetx / 2.0f) / range;
    523     right_factor.y = 1.0;
    524     XCAM_ASSERT (right_factor.x > 0.0f && right_factor.x < 2.0f);
    525 
    526     uint32_t right_idx = (idx + 1) % _stitcher->get_camera_num ();
    527     center_x = (float) _stitcher->get_center (right_idx).slice_center_x;
    528     feature_center_x = (float)right_ovlap.pos_x + (right_ovlap.width / 2.0f);
    529     range = center_x - feature_center_x;
    530     XCAM_ASSERT (range > 1.0f);
    531     left_factor.x = (range + left_offsetx / 2.0f) / range;
    532     left_factor.y = 1.0;
    533     XCAM_ASSERT (left_factor.x > 0.0f && left_factor.x < 2.0f);
    534 
    535     {
    536         SmartLock locker (_map_mutex);
    537         _fisheye[left_idx].right_match_factor = right_factor;
    538         _fisheye[right_idx].left_match_factor = left_factor;
    539     }
    540 
    541     return XCAM_RETURN_NO_ERROR;
    542 }
    543 
    544 XCamReturn
    545 StitcherImpl::start_single_blender (
    546     const uint32_t idx,
    547     const SmartPtr<BlenderParam> &param)
    548 {
    549     SmartPtr<SoftBlender> blender = _overlaps[idx].blender;
    550     const Stitcher::ImageOverlapInfo &overlap_info = _stitcher->get_overlap (idx);
    551     uint32_t out_width, out_height;
    552     _stitcher->get_output_size (out_width, out_height);
    553 
    554     blender->set_output_size (out_width, out_height);
    555     blender->set_merge_window (overlap_info.out_area);
    556     blender->set_input_valid_area (overlap_info.left, 0);
    557     blender->set_input_valid_area (overlap_info.right, 1);
    558     blender->set_input_merge_area (overlap_info.left, 0);
    559     blender->set_input_merge_area (overlap_info.right, 1);
    560     return blender->execute_buffer (param, false);
    561 }
    562 
    563 XCamReturn
    564 StitcherImpl::start_overlap_tasks (
    565     const SmartPtr<SoftStitcher::StitcherParam> &param,
    566     const uint32_t idx, const SmartPtr<VideoBuffer> &buf)
    567 {
    568     SmartPtr<BlenderParam> cur_param, prev_param;
    569     const uint32_t camera_num = _stitcher->get_camera_num ();
    570     uint32_t pre_idx = (idx + camera_num - 1) % camera_num;
    571     XCamReturn ret = XCAM_RETURN_NO_ERROR;
    572     {
    573         SmartPtr<BlenderParam> param_b;
    574 
    575         SmartLock locker (_map_mutex);
    576         param_b = _overlaps[idx].find_blender_param_in_map (param, idx);
    577         param_b->in_buf = buf;
    578         if (param_b->in_buf.ptr () && param_b->in1_buf.ptr ()) {
    579             cur_param = param_b;
    580             _overlaps[idx].param_map.erase (param.ptr ());
    581         }
    582 
    583         param_b = _overlaps[pre_idx].find_blender_param_in_map (param, pre_idx);
    584         param_b->in1_buf = buf;
    585         if (param_b->in_buf.ptr () && param_b->in1_buf.ptr ()) {
    586             prev_param = param_b;
    587             _overlaps[pre_idx].param_map.erase (param.ptr ());
    588         }
    589     }
    590 
    591     if (cur_param.ptr ()) {
    592         cur_param->out_buf = param->out_buf;
    593         ret = start_single_blender (idx, cur_param);
    594         XCAM_FAIL_RETURN (
    595             ERROR, xcam_ret_is_ok (ret), ret,
    596             "soft-stitcher:%s blend overlap idx:%d failed", XCAM_STR (_stitcher->get_name ()), idx);
    597     }
    598 
    599     if (prev_param.ptr ()) {
    600         prev_param->out_buf = param->out_buf;
    601         ret = start_single_blender (pre_idx, prev_param);
    602         XCAM_FAIL_RETURN (
    603             ERROR, xcam_ret_is_ok (ret), ret,
    604             "soft-stitcher:%s blend overlap idx:%d failed", XCAM_STR (_stitcher->get_name ()), pre_idx);
    605     }
    606 
    607 #if ENABLE_FEATURE_MATCH
    608     //start feature match
    609     if (cur_param.ptr ()) {
    610         ret = feature_match (cur_param->in_buf, cur_param->in1_buf, idx);
    611         XCAM_FAIL_RETURN (
    612             ERROR, xcam_ret_is_ok (ret), ret,
    613             "soft-stitcher:%s feature-match overlap idx:%d failed", XCAM_STR (_stitcher->get_name ()), idx);
    614     }
    615 
    616     if (prev_param.ptr ()) {
    617         ret = feature_match (prev_param->in_buf, prev_param->in1_buf, pre_idx);
    618         XCAM_FAIL_RETURN (
    619             ERROR, xcam_ret_is_ok (ret), ret,
    620             "soft-stitcher:%s feature-match overlap idx:%d failed", XCAM_STR (_stitcher->get_name ()), pre_idx);
    621     }
    622 #endif
    623     return XCAM_RETURN_NO_ERROR;
    624 }
    625 
    626 XCamReturn
    627 Copier::start_copy_task (
    628     const SmartPtr<ImageHandler::Parameters> &param,
    629     const uint32_t idx, const SmartPtr<VideoBuffer> &buf)
    630 {
    631     XCAM_ASSERT (copy_task.ptr ());
    632 
    633     SmartPtr<VideoBuffer> in_buf = buf, out_buf = param->out_buf;
    634     const VideoBufferInfo &in_info = in_buf->get_video_info ();
    635     const VideoBufferInfo &out_info = out_buf->get_video_info ();
    636 
    637     SmartPtr<StitcherCopyArgs> args = new StitcherCopyArgs (idx, param);
    638     args->in_luma = new UcharImage (
    639         in_buf, copy_area.in_area.width, copy_area.in_area.height, in_info.strides[0],
    640         in_info.offsets[0] + copy_area.in_area.pos_x + copy_area.in_area.pos_y * in_info.strides[0]);
    641     args->in_uv = new Uchar2Image (
    642         in_buf, copy_area.in_area.width / 2, copy_area.in_area.height / 2, in_info.strides[0],
    643         in_info.offsets[1] + copy_area.in_area.pos_x + copy_area.in_area.pos_y / 2 * in_info.strides[1]);
    644 
    645     args->out_luma = new UcharImage (
    646         out_buf, copy_area.out_area.width, copy_area.out_area.height, out_info.strides[0],
    647         out_info.offsets[0] + copy_area.out_area.pos_x + copy_area.out_area.pos_y * out_info.strides[0]);
    648     args->out_uv = new Uchar2Image (
    649         out_buf, copy_area.out_area.width / 2, copy_area.out_area.height / 2, out_info.strides[0],
    650         out_info.offsets[1] + copy_area.out_area.pos_x + copy_area.out_area.pos_y / 2 * out_info.strides[1]);
    651 
    652     uint32_t thread_x = 1, thread_y = 4;
    653     WorkSize global_size (1, xcam_ceil (copy_area.in_area.height, 2) / 2);
    654     WorkSize local_size (
    655         xcam_ceil (global_size.value[0], thread_x) / thread_x,
    656         xcam_ceil (global_size.value[1], thread_y) / thread_y);
    657 
    658     copy_task->set_local_size (local_size);
    659     copy_task->set_global_size (global_size);
    660 
    661     return copy_task->work (args);
    662 }
    663 
    664 XCamReturn
    665 StitcherImpl::start_copy_tasks (
    666     const SmartPtr<SoftStitcher::StitcherParam> &param,
    667     const uint32_t idx, const SmartPtr<VideoBuffer> &buf)
    668 {
    669     uint32_t size = _stitcher->get_copy_area ().size ();
    670     for (uint32_t i = 0; i < size; ++i) {
    671         if(_copiers[i].copy_area.in_idx == idx) {
    672             XCamReturn ret = _copiers[i].start_copy_task (param, idx, buf);
    673             XCAM_FAIL_RETURN (
    674                 ERROR, xcam_ret_is_ok (ret), ret,
    675                 "soft-stitcher:%s start copy task failed, idx:%d", XCAM_STR (_stitcher->get_name ()), idx);
    676         }
    677     }
    678 
    679     return XCAM_RETURN_NO_ERROR;
    680 }
    681 
    682 XCamReturn
    683 StitcherImpl::stop ()
    684 {
    685     uint32_t cam_num = _stitcher->get_camera_num ();
    686     for (uint32_t i = 0; i < cam_num; ++i) {
    687         if (_fisheye[i].dewarp.ptr ()) {
    688             _fisheye[i].dewarp->terminate ();
    689             _fisheye[i].dewarp.release ();
    690         }
    691         if (_fisheye[i].buf_pool.ptr ()) {
    692             _fisheye[i].buf_pool->stop ();
    693         }
    694 
    695         if (_overlaps[i].blender.ptr ()) {
    696             _overlaps[i].blender->terminate ();
    697             _overlaps[i].blender.release ();
    698         }
    699     }
    700 
    701     for (Copiers::iterator i_copy = _copiers.begin (); i_copy != _copiers.end (); ++i_copy) {
    702         Copier &copy = *i_copy;
    703         if (copy.copy_task.ptr ()) {
    704             copy.copy_task->stop ();
    705             copy.copy_task.release ();
    706         }
    707     }
    708 
    709     if (_dewarp_pool.ptr ()) {
    710         _dewarp_pool->stop ();
    711     }
    712     return XCAM_RETURN_NO_ERROR;
    713 }
    714 
    715 };
    716 
    717 SoftStitcher::SoftStitcher (const char *name)
    718     : SoftHandler (name)
    719     , Stitcher (SOFT_STITCHER_ALIGNMENT_X, SOFT_STITCHER_ALIGNMENT_Y)
    720 {
    721     _impl = new SoftSitcherPriv::StitcherImpl (this);
    722     XCAM_ASSERT (_impl.ptr ());
    723 #if ENABLE_FEATURE_MATCH
    724 #ifndef ANDROID
    725     cv::ocl::setUseOpenCL (false);
    726 #endif
    727 #endif
    728 }
    729 
    730 SoftStitcher::~SoftStitcher ()
    731 {
    732 }
    733 
    734 XCamReturn
    735 SoftStitcher::stitch_buffers (const VideoBufferList &in_bufs, SmartPtr<VideoBuffer> &out_buf)
    736 {
    737     XCAM_FAIL_RETURN (
    738         ERROR, !in_bufs.empty (), XCAM_RETURN_ERROR_PARAM,
    739         "soft-stitcher:%s stitch buffer failed, in_bufs is empty", XCAM_STR (get_name ()));
    740 
    741     SmartPtr<StitcherParam> param = new StitcherParam;
    742     param->out_buf = out_buf;
    743     uint32_t count = 0;
    744     for (VideoBufferList::const_iterator i = in_bufs.begin(); i != in_bufs.end (); ++i) {
    745         SmartPtr<VideoBuffer> buf = *i;
    746         XCAM_ASSERT (buf.ptr ());
    747         param->in_bufs[count++] = buf;
    748     }
    749     param->in_buf_num = count;
    750     XCamReturn ret = execute_buffer (param, true);
    751     if (!out_buf.ptr () && xcam_ret_is_ok (ret)) {
    752         out_buf = param->out_buf;
    753     }
    754     return ret;
    755 }
    756 
    757 XCamReturn
    758 SoftStitcher::terminate ()
    759 {
    760     _impl->stop ();
    761     return SoftHandler::terminate ();
    762 }
    763 
    764 XCamReturn
    765 SoftStitcher::start_task_count (const SmartPtr<SoftStitcher::StitcherParam> &param)
    766 {
    767     XCAM_ASSERT (param.ptr ());
    768     XCAM_ASSERT (_impl.ptr ());
    769 
    770     SmartLock locker (_impl->_map_mutex);
    771 
    772     XCAM_FAIL_RETURN (
    773         ERROR, check_work_continue (param, XCAM_RETURN_NO_ERROR), XCAM_RETURN_ERROR_PARAM,
    774         "soft-stitcher:%s start task count failed in work check", XCAM_STR (get_name ()));
    775 
    776     if (_impl->_task_counts.find (param.ptr ()) != _impl->_task_counts.end ()) {
    777         XCAM_LOG_ERROR ("tasks already started, this should never happen.");
    778         return XCAM_RETURN_ERROR_UNKNOWN;
    779     }
    780 
    781     int32_t count = get_camera_num ();
    782     count += get_copy_area ().size ();
    783 
    784     XCAM_LOG_DEBUG ("stitcher :%s start task count :%d", XCAM_STR(get_name ()), count);
    785     _impl->_task_counts.insert (std::make_pair((void*)param.ptr(), count));
    786     return XCAM_RETURN_NO_ERROR;
    787 }
    788 
    789 void
    790 SoftStitcher::dewarp_done (
    791     const SmartPtr<ImageHandler> &handler,
    792     const SmartPtr<ImageHandler::Parameters> &base,
    793     const XCamReturn error)
    794 {
    795     SmartPtr<SoftSitcherPriv::HandlerParam> dewarp_param = base.dynamic_cast_ptr<SoftSitcherPriv::HandlerParam> ();
    796     XCAM_ASSERT (dewarp_param.ptr ());
    797     SmartPtr<SoftStitcher::StitcherParam> param = dewarp_param->stitch_param;
    798     XCAM_ASSERT (param.ptr ());
    799     XCAM_UNUSED (handler);
    800 
    801     if (!check_work_continue (param, error))
    802         return;
    803 
    804     XCAM_LOG_INFO ("soft-stitcher:%s camera(idx:%d) dewarp done", XCAM_STR (get_name ()), dewarp_param->idx);
    805     stitcher_dump_buf (dewarp_param->out_buf, dewarp_param->idx, "stitcher-dewarp");
    806 
    807     //start both blender and feature match
    808     XCamReturn ret = _impl->start_overlap_tasks (param, dewarp_param->idx, dewarp_param->out_buf);
    809     if (!xcam_ret_is_ok (ret)) {
    810         work_broken (param, ret);
    811     }
    812 
    813     ret = _impl->start_copy_tasks (param, dewarp_param->idx, dewarp_param->out_buf);
    814     if (!xcam_ret_is_ok (ret)) {
    815         work_broken (param, ret);
    816     }
    817 }
    818 
    819 void
    820 SoftStitcher::blender_done (
    821     const SmartPtr<ImageHandler> &handler,
    822     const SmartPtr<ImageHandler::Parameters> &base,
    823     const XCamReturn error)
    824 {
    825     SmartPtr<SoftSitcherPriv::BlenderParam> blender_param = base.dynamic_cast_ptr<SoftSitcherPriv::BlenderParam> ();
    826     XCAM_ASSERT (blender_param.ptr ());
    827     SmartPtr<SoftStitcher::StitcherParam> param = blender_param->stitch_param;
    828     XCAM_ASSERT (param.ptr ());
    829     XCAM_UNUSED (handler);
    830 
    831     if (!check_work_continue (param, error)) {
    832         _impl->remove_task_count (param);
    833         return;
    834     }
    835 
    836     stitcher_dump_buf (blender_param->out_buf, blender_param->idx, "stitcher-blend");
    837     XCAM_LOG_INFO ("blender:(%s) overlap:%d done", XCAM_STR (handler->get_name ()), blender_param->idx);
    838 
    839     if (_impl->dec_task_count (param) == 0) {
    840         work_well_done (param, error);
    841     }
    842 }
    843 
    844 void
    845 SoftStitcher::copy_task_done (
    846     const SmartPtr<Worker> &worker,
    847     const SmartPtr<Worker::Arguments> &base,
    848     const XCamReturn error)
    849 {
    850     XCAM_UNUSED (worker);
    851     XCAM_ASSERT (worker.ptr ());
    852     SmartPtr<SoftSitcherPriv::StitcherCopyArgs> args = base.dynamic_cast_ptr<SoftSitcherPriv::StitcherCopyArgs> ();
    853     XCAM_ASSERT (args.ptr ());
    854     const SmartPtr<SoftStitcher::StitcherParam> param =
    855         args->get_param ().dynamic_cast_ptr<SoftStitcher::StitcherParam> ();
    856     XCAM_ASSERT (param.ptr ());
    857 
    858     if (!check_work_continue (param, error)) {
    859         _impl->remove_task_count (param);
    860         return;
    861     }
    862     XCAM_LOG_INFO ("soft-stitcher:%s camera(idx:%d) copy done", XCAM_STR (get_name ()), args->idx);
    863 
    864     if (_impl->dec_task_count (param) == 0) {
    865         work_well_done (param, error);
    866     }
    867 }
    868 
    869 XCamReturn
    870 SoftStitcher::configure_resource (const SmartPtr<Parameters> &param)
    871 {
    872     XCAM_UNUSED (param);
    873     XCAM_ASSERT (_impl.ptr ());
    874 
    875     XCamReturn ret = estimate_round_slices ();
    876     XCAM_FAIL_RETURN (
    877         ERROR, xcam_ret_is_ok (ret), ret,
    878         "soft-stitcher:%s estimate round view slices failed", XCAM_STR (get_name ()));
    879 
    880     ret = estimate_coarse_crops ();
    881     XCAM_FAIL_RETURN (
    882         ERROR, xcam_ret_is_ok (ret), ret,
    883         "soft-stitcher:%s estimate coarse crops failed", XCAM_STR (get_name ()));
    884 
    885     ret = mark_centers ();
    886     XCAM_FAIL_RETURN (
    887         ERROR, xcam_ret_is_ok (ret), ret,
    888         "soft-stitcher:%s mark centers failed", XCAM_STR (get_name ()));
    889 
    890     ret = estimate_overlap ();
    891     XCAM_FAIL_RETURN (
    892         ERROR, xcam_ret_is_ok (ret), ret,
    893         "soft-stitcher:%s estimake coarse overlap failed", XCAM_STR (get_name ()));
    894 
    895     ret = update_copy_areas ();
    896     XCAM_FAIL_RETURN (
    897         ERROR, xcam_ret_is_ok (ret), ret,
    898         "soft-stitcher:%s update copy areas failed", XCAM_STR (get_name ()));
    899 
    900     uint32_t camera_count = get_camera_num ();
    901     ret = _impl->init_config (camera_count);
    902     XCAM_FAIL_RETURN (
    903         ERROR, xcam_ret_is_ok (ret), ret,
    904         "soft-stitcher:%s initialize private config failed", XCAM_STR (get_name ()));
    905 
    906     ret = _impl->fisheye_dewarp_to_table ();
    907     XCAM_FAIL_RETURN (
    908         ERROR, xcam_ret_is_ok (ret), ret,
    909         "soft-stitcher:%s fisheye_dewarp_to_table failed", XCAM_STR (get_name ()));
    910 
    911     VideoBufferInfo out_info;
    912     uint32_t out_width, out_height;
    913     get_output_size (out_width, out_height);
    914     XCAM_FAIL_RETURN (
    915         ERROR, out_width && out_height, XCAM_RETURN_ERROR_PARAM,
    916         "soft-stitcher:%s output size was not set", XCAM_STR(get_name ()));
    917 
    918     out_info.init (
    919         V4L2_PIX_FMT_NV12, out_width, out_height,
    920         XCAM_ALIGN_UP (out_width, SOFT_STITCHER_ALIGNMENT_X),
    921         XCAM_ALIGN_UP (out_height, SOFT_STITCHER_ALIGNMENT_Y));
    922     set_out_video_info (out_info);
    923 
    924     return ret;
    925 }
    926 
    927 XCamReturn
    928 SoftStitcher::start_work (const SmartPtr<Parameters> &base)
    929 {
    930     SmartPtr<StitcherParam> param = base.dynamic_cast_ptr<StitcherParam> ();
    931 
    932     XCAM_FAIL_RETURN (
    933         ERROR, param.ptr () && param->in_buf_num > 0 && param->in_bufs[0].ptr (), XCAM_RETURN_ERROR_PARAM,
    934         "soft_stitcher:%s start_work failed, params(in_buf_num) in_bufs are set",
    935         XCAM_STR (get_name ()));
    936 
    937     XCamReturn ret = start_task_count (param);
    938     XCAM_FAIL_RETURN (
    939         ERROR, xcam_ret_is_ok (ret), XCAM_RETURN_ERROR_PARAM,
    940         "soft_stitcher:%s start blender count failed", XCAM_STR (get_name ()));
    941 
    942     ret = _impl->start_dewarp_works (param);
    943     XCAM_FAIL_RETURN (
    944         ERROR, xcam_ret_is_ok (ret), XCAM_RETURN_ERROR_PARAM,
    945         "soft_stitcher:%s start dewarp works failed", XCAM_STR (get_name ()));
    946 
    947     //for (uint32_t i = 0; i < param->in_buf_num; ++i) {
    948     //    param->in_bufs[i].release ();
    949     //}
    950 
    951     return ret;
    952 }
    953 
    954 SmartPtr<Stitcher>
    955 Stitcher::create_soft_stitcher ()
    956 {
    957     return new SoftStitcher;
    958 }
    959 
    960 }
    961 
    962