• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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
stitcher_dump_buf(const SmartPtr<VideoBuffer> buf,uint32_t idx,const char * prefix)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 
BlenderParamXCam::SoftSitcherPriv::BlenderParam78     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 
HandlerParamXCam::SoftSitcherPriv::HandlerParam97     HandlerParam (uint32_t i)
98         : idx (i)
99     {}
100 };
101 
102 struct StitcherCopyArgs
103     : XCamSoftTasks::CopyTask::Args
104 {
105     uint32_t idx;
106 
StitcherCopyArgsXCam::SoftSitcherPriv::StitcherCopyArgs107     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 
FactorXCam::SoftSitcherPriv::Factor118     Factor () : x (1.0f), y (1.0f) {}
resetXCam::SoftSitcherPriv::Factor119     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:
StitcherImpl(SoftStitcher * handler)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
init_dewarp_factors(uint32_t idx)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
set_dewarp_geo_table(SmartPtr<SoftGeoMapper> mapper,const CameraInfo & cam_info,const Stitcher::RoundViewSlice & view_slice,const BowlDataConfig & bowl)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
get_and_reset_feature_match_factors(uint32_t idx,Factor & left,Factor & right)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
init_fisheye(uint32_t idx)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
create_copier(Stitcher::CopyArea area)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
init_config(uint32_t count)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
remove_task_count(const SmartPtr<SoftStitcher::StitcherParam> & param)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
dec_task_count(const SmartPtr<SoftStitcher::StitcherParam> & param)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
fisheye_dewarp_to_table()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
start_dewarp_works(const SmartPtr<SoftStitcher::StitcherParam> & param)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>
find_blender_param_in_map(const SmartPtr<SoftStitcher::StitcherParam> & key,const uint32_t idx)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
feature_match(const SmartPtr<VideoBuffer> & left_buf,const SmartPtr<VideoBuffer> & right_buf,const uint32_t idx)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
start_single_blender(const uint32_t idx,const SmartPtr<BlenderParam> & param)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
start_overlap_tasks(const SmartPtr<SoftStitcher::StitcherParam> & param,const uint32_t idx,const SmartPtr<VideoBuffer> & buf)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
start_copy_task(const SmartPtr<ImageHandler::Parameters> & param,const uint32_t idx,const SmartPtr<VideoBuffer> & buf)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
start_copy_tasks(const SmartPtr<SoftStitcher::StitcherParam> & param,const uint32_t idx,const SmartPtr<VideoBuffer> & buf)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
stop()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 
SoftStitcher(const char * name)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 
~SoftStitcher()730 SoftStitcher::~SoftStitcher ()
731 {
732 }
733 
734 XCamReturn
stitch_buffers(const VideoBufferList & in_bufs,SmartPtr<VideoBuffer> & out_buf)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
terminate()758 SoftStitcher::terminate ()
759 {
760     _impl->stop ();
761     return SoftHandler::terminate ();
762 }
763 
764 XCamReturn
start_task_count(const SmartPtr<SoftStitcher::StitcherParam> & param)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
dewarp_done(const SmartPtr<ImageHandler> & handler,const SmartPtr<ImageHandler::Parameters> & base,const XCamReturn error)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
blender_done(const SmartPtr<ImageHandler> & handler,const SmartPtr<ImageHandler::Parameters> & base,const XCamReturn error)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
copy_task_done(const SmartPtr<Worker> & worker,const SmartPtr<Worker::Arguments> & base,const XCamReturn error)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
configure_resource(const SmartPtr<Parameters> & param)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
start_work(const SmartPtr<Parameters> & base)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>
create_soft_stitcher()955 Stitcher::create_soft_stitcher ()
956 {
957     return new SoftStitcher;
958 }
959 
960 }
961 
962