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
48namespace XCam {
49
50#if DUMP_STITCHER
51static void
52stitcher_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
60static void stitcher_dump_buf (const SmartPtr<VideoBuffer> buf, ...) {
61    XCAM_UNUSED (buf);
62}
63#endif
64
65
66namespace SoftSitcherPriv {
67
68DECLARE_HANDLER_CALLBACK (CbGeoMap, SoftStitcher, dewarp_done);
69DECLARE_HANDLER_CALLBACK (CbBlender, SoftStitcher, blender_done);
70DECLARE_WORK_CALLBACK (CbCopyTask, SoftStitcher, copy_task_done);
71
72struct 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
88typedef std::map<void*, SmartPtr<BlenderParam>> BlenderParams;
89typedef std::map<void*, int32_t> BlendCopyTaskNums;
90
91struct 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
102struct 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
115struct 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
125struct 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
135struct 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
148struct 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};
156typedef std::vector<Copier>    Copiers;
157
158class StitcherImpl {
159    friend class XCam::SoftStitcher;
160
161public:
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
191private:
192    XCamReturn init_fisheye (uint32_t idx);
193    bool init_dewarp_factors (uint32_t idx);
194    XCamReturn create_copier (Stitcher::CopyArea area);
195
196private:
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
208bool
209StitcherImpl::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
239XCamReturn
240FisheyeDewarp::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
266bool
267StitcherImpl::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
283XCamReturn
284StitcherImpl::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
310XCamReturn
311StitcherImpl::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
332XCamReturn
333StitcherImpl::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
388bool
389StitcherImpl::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
401int32_t
402StitcherImpl::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
420XCamReturn
421StitcherImpl::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
454XCamReturn
455StitcherImpl::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
476SmartPtr<BlenderParam>
477Overlap::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
495XCamReturn
496StitcherImpl::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
544XCamReturn
545StitcherImpl::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
563XCamReturn
564StitcherImpl::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
626XCamReturn
627Copier::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
664XCamReturn
665StitcherImpl::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
682XCamReturn
683StitcherImpl::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
717SoftStitcher::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
730SoftStitcher::~SoftStitcher ()
731{
732}
733
734XCamReturn
735SoftStitcher::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
757XCamReturn
758SoftStitcher::terminate ()
759{
760    _impl->stop ();
761    return SoftHandler::terminate ();
762}
763
764XCamReturn
765SoftStitcher::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
789void
790SoftStitcher::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
819void
820SoftStitcher::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
844void
845SoftStitcher::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
869XCamReturn
870SoftStitcher::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
927XCamReturn
928SoftStitcher::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
954SmartPtr<Stitcher>
955Stitcher::create_soft_stitcher ()
956{
957    return new SoftStitcher;
958}
959
960}
961
962