Home | History | Annotate | Download | only in tests
      1 /*
      2  * test-soft-image.cpp - test soft image
      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 "test_common.h"
     22 #include "test_inline.h"
     23 #include <buffer_pool.h>
     24 #include <image_handler.h>
     25 #include <image_file_handle.h>
     26 #include <soft/soft_video_buf_allocator.h>
     27 #include <interface/blender.h>
     28 #include <interface/geo_mapper.h>
     29 #include <interface/stitcher.h>
     30 #include <calibration_parser.h>
     31 #include <string>
     32 
     33 #if (!defined(ANDROID) && (HAVE_OPENCV))
     34 #include <ocl/cv_base_class.h>
     35 #endif
     36 
     37 #define XCAM_TEST_SOFT_IMAGE_DEBUG 0
     38 
     39 #if (!defined(ANDROID) && (HAVE_OPENCV))
     40 #define XCAM_TEST_OPENCV 1
     41 #else
     42 #define XCAM_TEST_OPENCV 0
     43 #endif
     44 
     45 #define XCAM_TEST_MAX_STR_SIZE 1024
     46 
     47 #define FISHEYE_CONFIG_PATH "./"
     48 
     49 #define MAP_WIDTH 3
     50 #define MAP_HEIGHT 4
     51 
     52 static PointFloat2 map_table[MAP_HEIGHT * MAP_WIDTH] = {
     53     {160.0f, 120.0f}, {480.0f, 120.0f}, {796.0f, 120.0f},
     54     {60.0f, 240.0f}, {480.0f, 240.0f}, {900.0f, 240.0f},
     55     {16.0f, 360.0f}, {480.0f, 360.0f}, {944.0f, 360.0f},
     56     {0.0f, 480.0f}, {480.0f, 480.0f}, {960.0f, 480.0f},
     57 };
     58 
     59 using namespace XCam;
     60 
     61 enum SoftType {
     62     SoftTypeNone     = 0,
     63     SoftTypeBlender,
     64     SoftTypeRemap,
     65     SoftTypeStitch,
     66 };
     67 
     68 #define RUN_N(statement, loop, msg, ...) \
     69     for (int i = 0; i < loop; ++i) {                          \
     70         CHECK (statement, msg, ## __VA_ARGS__);               \
     71         FPS_CALCULATION (soft-image, XCAM_OBJ_DUR_FRAME_NUM); \
     72     }
     73 
     74 #define ADD_ENELEMT(elements, file_name) \
     75     {                                                                \
     76         SmartPtr<SoftElement> element = new SoftElement (file_name); \
     77         elements.push_back (element);                                \
     78     }
     79 
     80 #if XCAM_TEST_OPENCV
     81 const static cv::Scalar color = cv::Scalar (0, 0, 255);
     82 const static int fontFace = cv::FONT_HERSHEY_COMPLEX;
     83 #endif
     84 
     85 class SoftElement {
     86 public:
     87     explicit SoftElement (const char *file_name = NULL, uint32_t width = 0, uint32_t height = 0);
     88     ~SoftElement ();
     89 
     90     void set_buf_size (uint32_t width, uint32_t height);
     91     uint32_t get_width () const {
     92         return _width;
     93     }
     94     uint32_t get_height () const {
     95         return _height;
     96     }
     97 
     98     const char *get_file_name () const {
     99         return _file_name;
    100     }
    101 
    102     SmartPtr<VideoBuffer> &get_buf () {
    103         return _buf;
    104     }
    105 
    106     XCamReturn open_file (const char *option);
    107     XCamReturn close_file ();
    108     XCamReturn rewind_file ();
    109 
    110     XCamReturn read_buf ();
    111     XCamReturn write_buf ();
    112 
    113     XCamReturn create_buf_pool (const VideoBufferInfo &info, uint32_t count);
    114 
    115 #if XCAM_TEST_OPENCV
    116     XCamReturn cv_open_writer ();
    117     void cv_write_image (char *img_name, char *frame_str, char *idx_str = NULL);
    118 #endif
    119 
    120 private:
    121     char                 *_file_name;
    122     uint32_t              _width;
    123     uint32_t              _height;
    124     SmartPtr<VideoBuffer> _buf;
    125 
    126     ImageFileHandle       _file;
    127     SmartPtr<BufferPool>  _pool;
    128 #if XCAM_TEST_OPENCV
    129     cv::VideoWriter       _writer;
    130 #endif
    131 };
    132 
    133 typedef std::vector<SmartPtr<SoftElement>> SoftElements;
    134 
    135 SoftElement::SoftElement (const char *file_name, uint32_t width, uint32_t height)
    136     : _file_name (NULL)
    137     , _width (width)
    138     , _height (height)
    139 {
    140     if (file_name)
    141         _file_name = strndup (file_name, XCAM_TEST_MAX_STR_SIZE);
    142 }
    143 
    144 SoftElement::~SoftElement ()
    145 {
    146     _file.close ();
    147 
    148     if (_file_name)
    149         xcam_free (_file_name);
    150 }
    151 
    152 void
    153 SoftElement::set_buf_size (uint32_t width, uint32_t height)
    154 {
    155     _width = width;
    156     _height = height;
    157 }
    158 
    159 XCamReturn
    160 SoftElement::open_file (const char *option)
    161 {
    162     if (_file.open (_file_name, option) != XCAM_RETURN_NO_ERROR) {
    163         XCAM_LOG_ERROR ("open %s failed.", _file_name);
    164         return XCAM_RETURN_ERROR_FILE;
    165     }
    166 
    167     return XCAM_RETURN_NO_ERROR;
    168 }
    169 
    170 XCamReturn
    171 SoftElement::close_file ()
    172 {
    173     return _file.close ();
    174 }
    175 
    176 XCamReturn
    177 SoftElement::rewind_file ()
    178 {
    179     return _file.rewind ();
    180 }
    181 
    182 XCamReturn
    183 SoftElement::create_buf_pool (const VideoBufferInfo &info, uint32_t count)
    184 {
    185     _pool = new SoftVideoBufAllocator ();
    186     _pool->set_video_info (info);
    187     if (!_pool->reserve (count)) {
    188         XCAM_LOG_ERROR ("create buffer pool failed");
    189         return XCAM_RETURN_ERROR_MEM;
    190     }
    191 
    192     return XCAM_RETURN_NO_ERROR;
    193 }
    194 
    195 XCamReturn
    196 SoftElement::read_buf ()
    197 {
    198     _buf = _pool->get_buffer (_pool);
    199     XCAM_ASSERT (_buf.ptr ());
    200 
    201     return _file.read_buf (_buf);
    202 }
    203 
    204 XCamReturn
    205 SoftElement::write_buf () {
    206     return _file.write_buf (_buf);
    207 }
    208 
    209 #if XCAM_TEST_OPENCV
    210 XCamReturn
    211 SoftElement::cv_open_writer ()
    212 {
    213     XCAM_FAIL_RETURN (
    214         ERROR,
    215         _width && _height,
    216         XCAM_RETURN_ERROR_PARAM,
    217         "invalid size width:%d height:%d", _width, _height);
    218 
    219     cv::Size frame_size = cv::Size (_width, _height);
    220     if (!_writer.open (_file_name, CV_FOURCC('X', '2', '6', '4'), 30, frame_size)) {
    221         XCAM_LOG_ERROR ("open file %s failed", _file_name);
    222         return XCAM_RETURN_ERROR_FILE;
    223     }
    224 
    225     return XCAM_RETURN_NO_ERROR;
    226 }
    227 
    228 void
    229 SoftElement::cv_write_image (char *img_name, char *frame_str, char *idx_str)
    230 {
    231     cv::Mat mat;
    232 
    233 #if XCAM_TEST_SOFT_IMAGE_DEBUG
    234     convert_to_mat (_buf, mat);
    235 
    236     cv::putText (mat, frame_str, cv::Point(20, 50), fontFace, 2.0, color, 2, 8, false);
    237     if(idx_str)
    238         cv::putText (mat, idx_str, cv::Point(20, 110), fontFace, 2.0, color, 2, 8, false);
    239 
    240     cv::imwrite (img_name, mat);
    241 #else
    242     XCAM_UNUSED (img_name);
    243     XCAM_UNUSED (frame_str);
    244     XCAM_UNUSED (idx_str);
    245 #endif
    246 
    247     if (_writer.isOpened ()) {
    248         if (mat.empty())
    249             convert_to_mat (_buf, mat);
    250 
    251         _writer.write (mat);
    252     }
    253 }
    254 #endif
    255 
    256 static int
    257 parse_camera_info (const char *path, uint32_t idx, CameraInfo &info, uint32_t camera_count)
    258 {
    259     static const char *instrinsic_names[] = {
    260         "intrinsic_camera_front.txt", "intrinsic_camera_right.txt",
    261         "intrinsic_camera_rear.txt", "intrinsic_camera_left.txt"
    262     };
    263     static const char *exstrinsic_names[] = {
    264         "extrinsic_camera_front.txt", "extrinsic_camera_right.txt",
    265         "extrinsic_camera_rear.txt", "extrinsic_camera_left.txt"
    266     };
    267     static const float viewpoints_range[] = {64.0f, 160.0f, 64.0f, 160.0f};
    268 
    269     char intrinsic_path[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
    270     char extrinsic_path[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
    271     snprintf (intrinsic_path, XCAM_TEST_MAX_STR_SIZE, "%s/%s", path, instrinsic_names[idx]);
    272     snprintf (extrinsic_path, XCAM_TEST_MAX_STR_SIZE, "%s/%s", path, exstrinsic_names[idx]);
    273 
    274     CalibrationParser parser;
    275     CHECK (
    276         parser.parse_intrinsic_file (intrinsic_path, info.calibration.intrinsic),
    277         "parse intrinsic params (%s)failed.", intrinsic_path);
    278 
    279     CHECK (
    280         parser.parse_extrinsic_file (extrinsic_path, info.calibration.extrinsic),
    281         "parse extrinsic params (%s)failed.", extrinsic_path);
    282     info.calibration.extrinsic.trans_x += TEST_CAMERA_POSITION_OFFSET_X;
    283 
    284     info.angle_range = viewpoints_range[idx];
    285     info.round_angle_start = (idx * 360.0f / camera_count) - info.angle_range / 2.0f;
    286     return 0;
    287 }
    288 
    289 static void
    290 combine_name (const char *orig_name, const char *embedded_str, char *new_name)
    291 {
    292     const char *dir_delimiter = std::strrchr (orig_name, '/');
    293 
    294     if (dir_delimiter) {
    295         std::string path (orig_name, dir_delimiter - orig_name + 1);
    296         XCAM_ASSERT (path.c_str ());
    297         snprintf (new_name, XCAM_TEST_MAX_STR_SIZE, "%s%s_%s", path.c_str (), embedded_str, dir_delimiter + 1);
    298     } else {
    299         snprintf (new_name, XCAM_TEST_MAX_STR_SIZE, "%s_%s", embedded_str, orig_name);
    300     }
    301 }
    302 
    303 static void
    304 add_element (SoftElements &elements, const char *element_name, uint32_t width, uint32_t height)
    305 {
    306     char file_name[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
    307     combine_name (elements[0]->get_file_name (), element_name, file_name);
    308 
    309     SmartPtr<SoftElement> element = new SoftElement (file_name, width, height);
    310     elements.push_back (element);
    311 }
    312 
    313 static XCamReturn
    314 elements_open_file (const SoftElements &elements, const char *option, const bool &nv12_output)
    315 {
    316     XCamReturn ret = XCAM_RETURN_NO_ERROR;
    317 
    318     for (uint32_t i = 0; i < elements.size (); ++i) {
    319         if (nv12_output)
    320             ret = elements[i]->open_file (option);
    321 #if XCAM_TEST_OPENCV
    322         else
    323             ret = elements[i]->cv_open_writer ();
    324 #endif
    325 
    326         if (ret != XCAM_RETURN_NO_ERROR) {
    327             XCAM_LOG_ERROR ("open file(%s) failed", elements[i]->get_file_name ());
    328             break;
    329         }
    330     }
    331 
    332     return ret;
    333 }
    334 
    335 static XCamReturn
    336 remap_topview_buf (
    337     BowlModel &model,
    338     const SmartPtr<VideoBuffer> &buf,
    339     SmartPtr<VideoBuffer> &topview_buf,
    340     uint32_t topview_width, uint32_t topview_height)
    341 {
    342     BowlModel::PointMap points;
    343 
    344     uint32_t lut_w = topview_width / 4, lut_h = topview_height / 4;
    345     float length_mm = 0.0f, width_mm = 0.0f;
    346 
    347     model.get_max_topview_area_mm (length_mm, width_mm);
    348     XCAM_LOG_INFO ("Max Topview Area (L%.2fmm, W%.2fmm)", length_mm, width_mm);
    349 
    350     model.get_topview_rect_map (points, lut_w, lut_h);
    351     SmartPtr<GeoMapper> mapper = GeoMapper::create_soft_geo_mapper ();
    352     XCAM_ASSERT (mapper.ptr ());
    353     mapper->set_output_size (topview_width, topview_height);
    354     mapper->set_lookup_table (points.data (), lut_w, lut_h);
    355 
    356     XCamReturn ret = mapper->remap (buf, topview_buf);
    357     if (ret != XCAM_RETURN_NO_ERROR) {
    358         XCAM_LOG_ERROR ("remap stitched image to topview failed.");
    359         return ret;
    360     }
    361 
    362 #if 0
    363     BowlModel::VertexMap bowl_vertices;
    364     BowlModel::PointMap bowl_points;
    365     uint32_t bowl_lut_w = 15, bowl_lut_h = 10;
    366     model.get_bowlview_vertex_map (bowl_vertices, bowl_points, bowl_lut_w, bowl_lut_h);
    367     for (uint32_t i = 0; i < bowl_lut_h; ++i) {
    368         for (uint32_t j = 0; j < bowl_lut_w; ++j)
    369         {
    370             PointFloat3 &vetex = bowl_vertices[i * bowl_lut_w + j];
    371             printf ("(%4.0f, %4.0f, %4.0f), ", vetex.x, vetex.y, vetex.z );
    372         }
    373         printf ("\n");
    374     }
    375 #endif
    376 
    377     return XCAM_RETURN_NO_ERROR;
    378 }
    379 
    380 static void
    381 write_image (const SoftElements &ins, const SoftElements &outs, const bool &nv12_output) {
    382     if (nv12_output) {
    383         for (uint32_t i = 0; i < outs.size (); ++i)
    384             outs[i]->write_buf ();
    385     }
    386 #if XCAM_TEST_OPENCV
    387     else {
    388         static uint32_t frame_num = 0;
    389         char img_name[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
    390         char frame_str[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
    391         std::snprintf (frame_str, XCAM_TEST_MAX_STR_SIZE, "frame:%d", frame_num);
    392 
    393         char idx_str[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
    394         for (uint32_t i = 0; i < ins.size (); ++i) {
    395             std::snprintf (idx_str, XCAM_TEST_MAX_STR_SIZE, "idx:%d", i);
    396             std::snprintf (img_name, XCAM_TEST_MAX_STR_SIZE, "orig_fisheye_%d_%d.jpg", frame_num, i);
    397             ins[i]->cv_write_image (img_name, frame_str, idx_str);
    398         }
    399 
    400         for (uint32_t i = 0; i < outs.size (); ++i) {
    401             std::snprintf (img_name, XCAM_TEST_MAX_STR_SIZE, "%s_%d.jpg", outs[i]->get_file_name (), frame_num);
    402             outs[i]->cv_write_image (img_name, frame_str);
    403         }
    404         frame_num++;
    405     }
    406 #endif
    407 }
    408 
    409 static XCamReturn
    410 ensure_output_format (const char *file_name, const SoftType &type, bool &nv12_output)
    411 {
    412     char suffix[XCAM_TEST_MAX_STR_SIZE] = {'\0'};
    413     const char *ptr = std::strrchr (file_name, '.');
    414     std::snprintf (suffix, XCAM_TEST_MAX_STR_SIZE, "%s", ptr + 1);
    415     if (!strcasecmp (suffix, "mp4")) {
    416 #if XCAM_TEST_OPENCV
    417         if (type != SoftTypeStitch) {
    418             XCAM_LOG_ERROR ("only stitch type supports MP4 output format");
    419             return XCAM_RETURN_ERROR_PARAM;
    420         }
    421         nv12_output = false;
    422 #else
    423         XCAM_LOG_ERROR ("only supports NV12 output format");
    424         return XCAM_RETURN_ERROR_PARAM;
    425 #endif
    426     }
    427 
    428     return XCAM_RETURN_NO_ERROR;
    429 }
    430 
    431 static bool
    432 check_element (const SoftElements &elements, const uint32_t &idx)
    433 {
    434     if (idx >= elements.size ())
    435         return false;
    436 
    437     if (!elements[idx].ptr()) {
    438         XCAM_LOG_ERROR ("SoftElement(idx:%d) ptr is NULL", idx);
    439         return false;
    440     }
    441 
    442     XCAM_FAIL_RETURN (
    443         ERROR,
    444         elements[idx]->get_width () && elements[idx]->get_height (),
    445         false,
    446         "SoftElement(idx:%d): invalid parameters width:%d height:%d",
    447         idx, elements[idx]->get_width (), elements[idx]->get_height ());
    448 
    449     return true;
    450 }
    451 
    452 static XCamReturn
    453 check_elements (const SoftElements &elements)
    454 {
    455     for (uint32_t i = 0; i < elements.size (); ++i) {
    456         XCAM_FAIL_RETURN (
    457             ERROR,
    458             check_element (elements, i),
    459             XCAM_RETURN_ERROR_PARAM,
    460             "invalid SoftElement index:%d\n", i);
    461     }
    462 
    463     return XCAM_RETURN_NO_ERROR;
    464 }
    465 
    466 static XCamReturn
    467 run_topview (const SmartPtr<Stitcher> &stitcher, const SoftElements &outs)
    468 {
    469     BowlModel bowl_model (stitcher->get_bowl_config (), outs[0]->get_width (), outs[0]->get_height ());
    470     return remap_topview_buf (bowl_model, outs[0]->get_buf (), outs[1]->get_buf (),
    471                               outs[1]->get_width (), outs[1]->get_height ());
    472 }
    473 
    474 static int
    475 run_stitcher (
    476     const SmartPtr<Stitcher> &stitcher,
    477     const SoftElements &ins, const SoftElements &outs,
    478     bool nv12_output, bool save_output, int loop)
    479 {
    480     XCamReturn ret = XCAM_RETURN_NO_ERROR;
    481     CHECK (check_elements (ins), "invalid input elements");
    482     CHECK (check_elements (outs), "invalid output elements");
    483 
    484     VideoBufferList in_buffers;
    485     while (loop--) {
    486         for (uint32_t i = 0; i < ins.size (); ++i) {
    487             CHECK (ins[i]->rewind_file (), "rewind buffer from file(%s) failed", ins[i]->get_file_name ());
    488         }
    489 
    490         do {
    491             in_buffers.clear ();
    492 
    493             for (uint32_t i = 0; i < ins.size (); ++i) {
    494                 ret = ins[i]->read_buf();
    495                 if (ret == XCAM_RETURN_BYPASS)
    496                     break;
    497                 CHECK (ret, "read buffer from file(%s) failed.", ins[i]->get_file_name ());
    498 
    499                 in_buffers.push_back (ins[i]->get_buf ());
    500             }
    501             if (ret == XCAM_RETURN_BYPASS)
    502                 break;
    503 
    504             CHECK (
    505                 stitcher->stitch_buffers (in_buffers, outs[0]->get_buf ()),
    506                 "stitch buffer failed.");
    507 
    508             if (save_output) {
    509                 if (check_element (outs, 1)) {
    510                     CHECK (run_topview (stitcher, outs), "run topview failed");
    511                 }
    512 
    513                 write_image (ins, outs, nv12_output);
    514             }
    515 
    516             FPS_CALCULATION (soft - stitcher, XCAM_OBJ_DUR_FRAME_NUM);
    517         } while (true);
    518     }
    519 
    520     return 0;
    521 }
    522 
    523 static void usage(const char* arg0)
    524 {
    525     printf ("Usage:\n"
    526             "%s --type TYPE--input0 file0 --input1 file1 --output file\n"
    527             "\t--type              processing type, selected from: blend, remap, stitch, ...\n"
    528             "\t--                  [stitch]: read calibration files from exported path $FISHEYE_CONFIG_PATH\n"
    529             "\t--input0            input image(NV12)\n"
    530             "\t--input1            input image(NV12)\n"
    531             "\t--input2            input image(NV12)\n"
    532             "\t--input3            input image(NV12)\n"
    533             "\t--output            output image(NV12)\n"
    534             "\t--in-w              optional, input width, default: 1920\n"
    535             "\t--in-h              optional, input height, default: 1080\n"
    536             "\t--out-w             optional, output width, default: 1920\n"
    537             "\t--out-h             optional, output height, default: 960\n"
    538             "\t--topview-w         optional, output width, default: 1280\n"
    539             "\t--topview-h         optional, output height, default: 720\n"
    540             "\t--save              optional, save file or not, select from [true/false], default: true\n"
    541             "\t--loop              optional, how many loops need to run, default: 1\n"
    542             "\t--help              usage\n",
    543             arg0);
    544 }
    545 
    546 int main (int argc, char *argv[])
    547 {
    548     uint32_t input_width = 1920;
    549     uint32_t input_height = 1080;
    550     uint32_t output_width = 1920; //output_height * 2;
    551     uint32_t output_height = 960; //960;
    552     uint32_t topview_width = 1280;
    553     uint32_t topview_height = 720;
    554     SoftType type = SoftTypeNone;
    555 
    556     SoftElements ins;
    557     SoftElements outs;
    558 
    559     int loop = 1;
    560     bool save_output = true;
    561     bool nv12_output = true;
    562 
    563     const struct option long_opts[] = {
    564         {"type", required_argument, NULL, 't'},
    565         {"input0", required_argument, NULL, 'i'},
    566         {"input1", required_argument, NULL, 'j'},
    567         {"input2", required_argument, NULL, 'k'},
    568         {"input3", required_argument, NULL, 'l'},
    569         {"output", required_argument, NULL, 'o'},
    570         {"in-w", required_argument, NULL, 'w'},
    571         {"in-h", required_argument, NULL, 'h'},
    572         {"out-w", required_argument, NULL, 'W'},
    573         {"out-h", required_argument, NULL, 'H'},
    574         {"topview-w", required_argument, NULL, 'P'},
    575         {"topview-h", required_argument, NULL, 'V'},
    576         {"save", required_argument, NULL, 's'},
    577         {"loop", required_argument, NULL, 'L'},
    578         {"help", no_argument, NULL, 'e'},
    579         {NULL, 0, NULL, 0},
    580     };
    581 
    582     int opt = -1;
    583     while ((opt = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
    584         switch (opt) {
    585         case 't':
    586             XCAM_ASSERT (optarg);
    587             if (!strcasecmp (optarg, "blend"))
    588                 type = SoftTypeBlender;
    589             else if (!strcasecmp (optarg, "remap"))
    590                 type = SoftTypeRemap;
    591             else if (!strcasecmp (optarg, "stitch"))
    592                 type = SoftTypeStitch;
    593             else {
    594                 XCAM_LOG_ERROR ("unknown type:%s", optarg);
    595                 usage (argv[0]);
    596                 return -1;
    597             }
    598             break;
    599 
    600         case 'i':
    601             XCAM_ASSERT (optarg);
    602             ADD_ENELEMT(ins, optarg);
    603             break;
    604         case 'j':
    605             XCAM_ASSERT (optarg);
    606             ADD_ENELEMT(ins, optarg);
    607             break;
    608         case 'k':
    609             XCAM_ASSERT (optarg);
    610             ADD_ENELEMT(ins, optarg);
    611             break;
    612         case 'l':
    613             XCAM_ASSERT (optarg);
    614             ADD_ENELEMT(ins, optarg);
    615             break;
    616         case 'o':
    617             XCAM_ASSERT (optarg);
    618             ADD_ENELEMT(outs, optarg);
    619             break;
    620         case 'w':
    621             input_width = atoi(optarg);
    622             break;
    623         case 'h':
    624             input_height = atoi(optarg);
    625             break;
    626         case 'W':
    627             output_width = atoi(optarg);
    628             break;
    629         case 'H':
    630             output_height = atoi(optarg);
    631             break;
    632         case 'P':
    633             topview_width = atoi(optarg);
    634             break;
    635         case 'V':
    636             topview_height = atoi(optarg);
    637             break;
    638         case 's':
    639             save_output = (strcasecmp (optarg, "false") == 0 ? false : true);
    640             break;
    641         case 'L':
    642             loop = atoi(optarg);
    643             break;
    644         default:
    645             XCAM_LOG_ERROR ("getopt_long return unknown value:%c", opt);
    646             usage (argv[0]);
    647             return -1;
    648         }
    649     }
    650 
    651     if (optind < argc || argc < 2) {
    652         XCAM_LOG_ERROR ("unknown option %s", argv[optind]);
    653         usage (argv[0]);
    654         return -1;
    655     }
    656 
    657     if (SoftTypeNone == type) {
    658         XCAM_LOG_ERROR ("Type was not set");
    659         usage (argv[0]);
    660         return -1;
    661     }
    662 
    663     if (ins.empty () || outs.empty () ||
    664             !strlen (ins[0]->get_file_name ()) || !strlen (outs[0]->get_file_name ())) {
    665         XCAM_LOG_ERROR ("input or output file name was not set");
    666         usage (argv[0]);
    667         return -1;
    668     }
    669 
    670     for (uint32_t i = 0; i < ins.size (); ++i) {
    671         printf ("input%d file:\t\t%s\n", i, ins[i]->get_file_name ());
    672     }
    673     printf ("output file:\t\t%s\n", outs[0]->get_file_name ());
    674     printf ("input width:\t\t%d\n", input_width);
    675     printf ("input height:\t\t%d\n", input_height);
    676     printf ("output width:\t\t%d\n", output_width);
    677     printf ("output height:\t\t%d\n", output_height);
    678     printf ("topview width:\t\t%d\n", topview_width);
    679     printf ("topview height:\t\t%d\n", topview_height);
    680     printf ("save output:\t\t%s\n", save_output ? "true" : "false");
    681     printf ("loop count:\t\t%d\n", loop);
    682 
    683     VideoBufferInfo in_info, out_info;
    684     in_info.init (V4L2_PIX_FMT_NV12, input_width, input_height);
    685     out_info.init (V4L2_PIX_FMT_NV12, output_width, output_height);
    686 
    687     for (uint32_t i = 0; i < ins.size (); ++i) {
    688         ins[i]->set_buf_size (input_width, input_height);
    689         CHECK (ins[i]->create_buf_pool (in_info, 6), "create buffer pool failed");
    690         CHECK (ins[i]->open_file ("rb"), "open file(%s) failed", ins[i]->get_file_name ());
    691     }
    692 
    693     outs[0]->set_buf_size (output_width, output_height);
    694     if (save_output) {
    695         CHECK (ensure_output_format (outs[0]->get_file_name (), type, nv12_output), "unsupported output format");
    696         if (nv12_output) {
    697             CHECK (outs[0]->open_file ("wb"), "open file(%s) failed", outs[0]->get_file_name ());
    698         }
    699     }
    700 
    701     switch (type) {
    702     case SoftTypeBlender: {
    703         CHECK_EXP (ins.size () >= 2, "blender need 2 input files.");
    704         SmartPtr<Blender> blender = Blender::create_soft_blender ();
    705         XCAM_ASSERT (blender.ptr ());
    706         blender->set_output_size (output_width, output_height);
    707         Rect merge_window;
    708         merge_window.pos_x = 0;
    709         merge_window.pos_y = 0;
    710         merge_window.width = out_info.width;
    711         merge_window.height = out_info.height;
    712         blender->set_merge_window (merge_window);
    713 
    714         CHECK (ins[0]->read_buf(), "read buffer from file(%s) failed.", ins[0]->get_file_name ());
    715         CHECK (ins[1]->read_buf(), "read buffer from file(%s) failed.", ins[1]->get_file_name ());
    716         RUN_N (blender->blend (ins[0]->get_buf (), ins[1]->get_buf (), outs[0]->get_buf ()), loop, "blend buffer failed.");
    717         if (save_output)
    718             outs[0]->write_buf ();
    719         break;
    720     }
    721     case SoftTypeRemap: {
    722         SmartPtr<GeoMapper> mapper = GeoMapper::create_soft_geo_mapper ();
    723         XCAM_ASSERT (mapper.ptr ());
    724         mapper->set_output_size (output_width, output_height);
    725         mapper->set_lookup_table (map_table, MAP_WIDTH, MAP_HEIGHT);
    726         //mapper->set_factors ((output_width - 1.0f) / (MAP_WIDTH - 1.0f), (output_height - 1.0f) / (MAP_HEIGHT - 1.0f));
    727 
    728         CHECK (ins[0]->read_buf(), "read buffer from file(%s) failed.", ins[0]->get_file_name ());
    729         RUN_N (mapper->remap (ins[0]->get_buf (), outs[0]->get_buf ()), loop, "remap buffer failed.");
    730         if (save_output)
    731             outs[0]->write_buf ();
    732         break;
    733     }
    734     case SoftTypeStitch: {
    735         CHECK_EXP (ins.size () >= 2 && ins.size () <= 4, "stitcher need at 2~4 input files.");
    736 
    737         uint32_t camera_count = ins.size ();
    738         SmartPtr<Stitcher> stitcher = Stitcher::create_soft_stitcher ();
    739         XCAM_ASSERT (stitcher.ptr ());
    740 
    741         CameraInfo cam_info[4];
    742         const char *fisheye_config_path = getenv ("FISHEYE_CONFIG_PATH");
    743         if (!fisheye_config_path)
    744             fisheye_config_path = FISHEYE_CONFIG_PATH;
    745 
    746         for (uint32_t i = 0; i < camera_count; ++i) {
    747             if (parse_camera_info (fisheye_config_path, i, cam_info[i], camera_count) != 0) {
    748                 XCAM_LOG_ERROR ("parse fisheye dewarp info(idx:%d) failed.", i);
    749                 return -1;
    750             }
    751         }
    752 
    753         PointFloat3 bowl_coord_offset;
    754         if (camera_count == 4) {
    755             centralize_bowl_coord_from_cameras (
    756                 cam_info[0].calibration.extrinsic, cam_info[1].calibration.extrinsic,
    757                 cam_info[2].calibration.extrinsic, cam_info[3].calibration.extrinsic,
    758                 bowl_coord_offset);
    759         }
    760 
    761         stitcher->set_camera_num (camera_count);
    762         for (uint32_t i = 0; i < camera_count; ++i) {
    763             stitcher->set_camera_info (i, cam_info[i]);
    764         }
    765 
    766         BowlDataConfig bowl;
    767         bowl.wall_height = 3000.0f;
    768         bowl.ground_length = 2000.0f;
    769         //bowl.a = 5000.0f;
    770         //bowl.b = 3600.0f;
    771         //bowl.c = 3000.0f;
    772         bowl.angle_start = 0.0f;
    773         bowl.angle_end = 360.0f;
    774         stitcher->set_bowl_config (bowl);
    775         stitcher->set_output_size (output_width, output_height);
    776 
    777         if (save_output) {
    778             add_element (outs, "topview", topview_width, topview_height);
    779             elements_open_file (outs, "wb", nv12_output);
    780         }
    781         CHECK_EXP (
    782             run_stitcher (stitcher, ins, outs, nv12_output, save_output, loop) == 0,
    783             "run stitcher failed.");
    784         break;
    785     }
    786 
    787     default: {
    788         XCAM_LOG_ERROR ("unsupported type:%d", type);
    789         usage (argv[0]);
    790         return -1;
    791     }
    792     }
    793 
    794     return 0;
    795 }
    796