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