| /* |
| * test-soft-image.cpp - test soft image |
| * |
| * Copyright (c) 2017 Intel Corporation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| * Author: Wind Yuan <[email protected]> |
| */ |
| |
| #include "test_common.h" |
| #include "test_inline.h" |
| #include <buffer_pool.h> |
| #include <image_handler.h> |
| #include <image_file_handle.h> |
| #include <soft/soft_video_buf_allocator.h> |
| #include <interface/blender.h> |
| #include <interface/geo_mapper.h> |
| #include <interface/stitcher.h> |
| #include <calibration_parser.h> |
| #include <string> |
| |
| #if (!defined(ANDROID) && (HAVE_OPENCV)) |
| #include <ocl/cv_base_class.h> |
| #endif |
| |
| #define XCAM_TEST_SOFT_IMAGE_DEBUG 0 |
| |
| #if (!defined(ANDROID) && (HAVE_OPENCV)) |
| #define XCAM_TEST_OPENCV 1 |
| #else |
| #define XCAM_TEST_OPENCV 0 |
| #endif |
| |
| #define XCAM_TEST_MAX_STR_SIZE 1024 |
| |
| #define FISHEYE_CONFIG_PATH "./" |
| |
| #define MAP_WIDTH 3 |
| #define MAP_HEIGHT 4 |
| |
| static PointFloat2 map_table[MAP_HEIGHT * MAP_WIDTH] = { |
| {160.0f, 120.0f}, {480.0f, 120.0f}, {796.0f, 120.0f}, |
| {60.0f, 240.0f}, {480.0f, 240.0f}, {900.0f, 240.0f}, |
| {16.0f, 360.0f}, {480.0f, 360.0f}, {944.0f, 360.0f}, |
| {0.0f, 480.0f}, {480.0f, 480.0f}, {960.0f, 480.0f}, |
| }; |
| |
| using namespace XCam; |
| |
| enum SoftType { |
| SoftTypeNone = 0, |
| SoftTypeBlender, |
| SoftTypeRemap, |
| SoftTypeStitch, |
| }; |
| |
| #define RUN_N(statement, loop, msg, ...) \ |
| for (int i = 0; i < loop; ++i) { \ |
| CHECK (statement, msg, ## __VA_ARGS__); \ |
| FPS_CALCULATION (soft-image, XCAM_OBJ_DUR_FRAME_NUM); \ |
| } |
| |
| #define ADD_ENELEMT(elements, file_name) \ |
| { \ |
| SmartPtr<SoftElement> element = new SoftElement (file_name); \ |
| elements.push_back (element); \ |
| } |
| |
| #if XCAM_TEST_OPENCV |
| const static cv::Scalar color = cv::Scalar (0, 0, 255); |
| const static int fontFace = cv::FONT_HERSHEY_COMPLEX; |
| #endif |
| |
| class SoftElement { |
| public: |
| explicit SoftElement (const char *file_name = NULL, uint32_t width = 0, uint32_t height = 0); |
| ~SoftElement (); |
| |
| void set_buf_size (uint32_t width, uint32_t height); |
| uint32_t get_width () const { |
| return _width; |
| } |
| uint32_t get_height () const { |
| return _height; |
| } |
| |
| const char *get_file_name () const { |
| return _file_name; |
| } |
| |
| SmartPtr<VideoBuffer> &get_buf () { |
| return _buf; |
| } |
| |
| XCamReturn open_file (const char *option); |
| XCamReturn close_file (); |
| XCamReturn rewind_file (); |
| |
| XCamReturn read_buf (); |
| XCamReturn write_buf (); |
| |
| XCamReturn create_buf_pool (const VideoBufferInfo &info, uint32_t count); |
| |
| #if XCAM_TEST_OPENCV |
| XCamReturn cv_open_writer (); |
| void cv_write_image (char *img_name, char *frame_str, char *idx_str = NULL); |
| #endif |
| |
| private: |
| char *_file_name; |
| uint32_t _width; |
| uint32_t _height; |
| SmartPtr<VideoBuffer> _buf; |
| |
| ImageFileHandle _file; |
| SmartPtr<BufferPool> _pool; |
| #if XCAM_TEST_OPENCV |
| cv::VideoWriter _writer; |
| #endif |
| }; |
| |
| typedef std::vector<SmartPtr<SoftElement>> SoftElements; |
| |
| SoftElement::SoftElement (const char *file_name, uint32_t width, uint32_t height) |
| : _file_name (NULL) |
| , _width (width) |
| , _height (height) |
| { |
| if (file_name) |
| _file_name = strndup (file_name, XCAM_TEST_MAX_STR_SIZE); |
| } |
| |
| SoftElement::~SoftElement () |
| { |
| _file.close (); |
| |
| if (_file_name) |
| xcam_free (_file_name); |
| } |
| |
| void |
| SoftElement::set_buf_size (uint32_t width, uint32_t height) |
| { |
| _width = width; |
| _height = height; |
| } |
| |
| XCamReturn |
| SoftElement::open_file (const char *option) |
| { |
| if (_file.open (_file_name, option) != XCAM_RETURN_NO_ERROR) { |
| XCAM_LOG_ERROR ("open %s failed.", _file_name); |
| return XCAM_RETURN_ERROR_FILE; |
| } |
| |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| XCamReturn |
| SoftElement::close_file () |
| { |
| return _file.close (); |
| } |
| |
| XCamReturn |
| SoftElement::rewind_file () |
| { |
| return _file.rewind (); |
| } |
| |
| XCamReturn |
| SoftElement::create_buf_pool (const VideoBufferInfo &info, uint32_t count) |
| { |
| _pool = new SoftVideoBufAllocator (); |
| _pool->set_video_info (info); |
| if (!_pool->reserve (count)) { |
| XCAM_LOG_ERROR ("create buffer pool failed"); |
| return XCAM_RETURN_ERROR_MEM; |
| } |
| |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| XCamReturn |
| SoftElement::read_buf () |
| { |
| _buf = _pool->get_buffer (_pool); |
| XCAM_ASSERT (_buf.ptr ()); |
| |
| return _file.read_buf (_buf); |
| } |
| |
| XCamReturn |
| SoftElement::write_buf () { |
| return _file.write_buf (_buf); |
| } |
| |
| #if XCAM_TEST_OPENCV |
| XCamReturn |
| SoftElement::cv_open_writer () |
| { |
| XCAM_FAIL_RETURN ( |
| ERROR, |
| _width && _height, |
| XCAM_RETURN_ERROR_PARAM, |
| "invalid size width:%d height:%d", _width, _height); |
| |
| cv::Size frame_size = cv::Size (_width, _height); |
| if (!_writer.open (_file_name, CV_FOURCC('X', '2', '6', '4'), 30, frame_size)) { |
| XCAM_LOG_ERROR ("open file %s failed", _file_name); |
| return XCAM_RETURN_ERROR_FILE; |
| } |
| |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| void |
| SoftElement::cv_write_image (char *img_name, char *frame_str, char *idx_str) |
| { |
| cv::Mat mat; |
| |
| #if XCAM_TEST_SOFT_IMAGE_DEBUG |
| convert_to_mat (_buf, mat); |
| |
| cv::putText (mat, frame_str, cv::Point(20, 50), fontFace, 2.0, color, 2, 8, false); |
| if(idx_str) |
| cv::putText (mat, idx_str, cv::Point(20, 110), fontFace, 2.0, color, 2, 8, false); |
| |
| cv::imwrite (img_name, mat); |
| #else |
| XCAM_UNUSED (img_name); |
| XCAM_UNUSED (frame_str); |
| XCAM_UNUSED (idx_str); |
| #endif |
| |
| if (_writer.isOpened ()) { |
| if (mat.empty()) |
| convert_to_mat (_buf, mat); |
| |
| _writer.write (mat); |
| } |
| } |
| #endif |
| |
| static int |
| parse_camera_info (const char *path, uint32_t idx, CameraInfo &info, uint32_t camera_count) |
| { |
| static const char *instrinsic_names[] = { |
| "intrinsic_camera_front.txt", "intrinsic_camera_right.txt", |
| "intrinsic_camera_rear.txt", "intrinsic_camera_left.txt" |
| }; |
| static const char *exstrinsic_names[] = { |
| "extrinsic_camera_front.txt", "extrinsic_camera_right.txt", |
| "extrinsic_camera_rear.txt", "extrinsic_camera_left.txt" |
| }; |
| static const float viewpoints_range[] = {64.0f, 160.0f, 64.0f, 160.0f}; |
| |
| char intrinsic_path[XCAM_TEST_MAX_STR_SIZE] = {'\0'}; |
| char extrinsic_path[XCAM_TEST_MAX_STR_SIZE] = {'\0'}; |
| snprintf (intrinsic_path, XCAM_TEST_MAX_STR_SIZE, "%s/%s", path, instrinsic_names[idx]); |
| snprintf (extrinsic_path, XCAM_TEST_MAX_STR_SIZE, "%s/%s", path, exstrinsic_names[idx]); |
| |
| CalibrationParser parser; |
| CHECK ( |
| parser.parse_intrinsic_file (intrinsic_path, info.calibration.intrinsic), |
| "parse intrinsic params (%s)failed.", intrinsic_path); |
| |
| CHECK ( |
| parser.parse_extrinsic_file (extrinsic_path, info.calibration.extrinsic), |
| "parse extrinsic params (%s)failed.", extrinsic_path); |
| info.calibration.extrinsic.trans_x += TEST_CAMERA_POSITION_OFFSET_X; |
| |
| info.angle_range = viewpoints_range[idx]; |
| info.round_angle_start = (idx * 360.0f / camera_count) - info.angle_range / 2.0f; |
| return 0; |
| } |
| |
| static void |
| combine_name (const char *orig_name, const char *embedded_str, char *new_name) |
| { |
| const char *dir_delimiter = std::strrchr (orig_name, '/'); |
| |
| if (dir_delimiter) { |
| std::string path (orig_name, dir_delimiter - orig_name + 1); |
| XCAM_ASSERT (path.c_str ()); |
| snprintf (new_name, XCAM_TEST_MAX_STR_SIZE, "%s%s_%s", path.c_str (), embedded_str, dir_delimiter + 1); |
| } else { |
| snprintf (new_name, XCAM_TEST_MAX_STR_SIZE, "%s_%s", embedded_str, orig_name); |
| } |
| } |
| |
| static void |
| add_element (SoftElements &elements, const char *element_name, uint32_t width, uint32_t height) |
| { |
| char file_name[XCAM_TEST_MAX_STR_SIZE] = {'\0'}; |
| combine_name (elements[0]->get_file_name (), element_name, file_name); |
| |
| SmartPtr<SoftElement> element = new SoftElement (file_name, width, height); |
| elements.push_back (element); |
| } |
| |
| static XCamReturn |
| elements_open_file (const SoftElements &elements, const char *option, const bool &nv12_output) |
| { |
| XCamReturn ret = XCAM_RETURN_NO_ERROR; |
| |
| for (uint32_t i = 0; i < elements.size (); ++i) { |
| if (nv12_output) |
| ret = elements[i]->open_file (option); |
| #if XCAM_TEST_OPENCV |
| else |
| ret = elements[i]->cv_open_writer (); |
| #endif |
| |
| if (ret != XCAM_RETURN_NO_ERROR) { |
| XCAM_LOG_ERROR ("open file(%s) failed", elements[i]->get_file_name ()); |
| break; |
| } |
| } |
| |
| return ret; |
| } |
| |
| static XCamReturn |
| remap_topview_buf ( |
| BowlModel &model, |
| const SmartPtr<VideoBuffer> &buf, |
| SmartPtr<VideoBuffer> &topview_buf, |
| uint32_t topview_width, uint32_t topview_height) |
| { |
| BowlModel::PointMap points; |
| |
| uint32_t lut_w = topview_width / 4, lut_h = topview_height / 4; |
| float length_mm = 0.0f, width_mm = 0.0f; |
| |
| model.get_max_topview_area_mm (length_mm, width_mm); |
| XCAM_LOG_INFO ("Max Topview Area (L%.2fmm, W%.2fmm)", length_mm, width_mm); |
| |
| model.get_topview_rect_map (points, lut_w, lut_h); |
| SmartPtr<GeoMapper> mapper = GeoMapper::create_soft_geo_mapper (); |
| XCAM_ASSERT (mapper.ptr ()); |
| mapper->set_output_size (topview_width, topview_height); |
| mapper->set_lookup_table (points.data (), lut_w, lut_h); |
| |
| XCamReturn ret = mapper->remap (buf, topview_buf); |
| if (ret != XCAM_RETURN_NO_ERROR) { |
| XCAM_LOG_ERROR ("remap stitched image to topview failed."); |
| return ret; |
| } |
| |
| #if 0 |
| BowlModel::VertexMap bowl_vertices; |
| BowlModel::PointMap bowl_points; |
| uint32_t bowl_lut_w = 15, bowl_lut_h = 10; |
| model.get_bowlview_vertex_map (bowl_vertices, bowl_points, bowl_lut_w, bowl_lut_h); |
| for (uint32_t i = 0; i < bowl_lut_h; ++i) { |
| for (uint32_t j = 0; j < bowl_lut_w; ++j) |
| { |
| PointFloat3 &vetex = bowl_vertices[i * bowl_lut_w + j]; |
| printf ("(%4.0f, %4.0f, %4.0f), ", vetex.x, vetex.y, vetex.z ); |
| } |
| printf ("\n"); |
| } |
| #endif |
| |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| static void |
| write_image (const SoftElements &ins, const SoftElements &outs, const bool &nv12_output) { |
| if (nv12_output) { |
| for (uint32_t i = 0; i < outs.size (); ++i) |
| outs[i]->write_buf (); |
| } |
| #if XCAM_TEST_OPENCV |
| else { |
| static uint32_t frame_num = 0; |
| char img_name[XCAM_TEST_MAX_STR_SIZE] = {'\0'}; |
| char frame_str[XCAM_TEST_MAX_STR_SIZE] = {'\0'}; |
| std::snprintf (frame_str, XCAM_TEST_MAX_STR_SIZE, "frame:%d", frame_num); |
| |
| char idx_str[XCAM_TEST_MAX_STR_SIZE] = {'\0'}; |
| for (uint32_t i = 0; i < ins.size (); ++i) { |
| std::snprintf (idx_str, XCAM_TEST_MAX_STR_SIZE, "idx:%d", i); |
| std::snprintf (img_name, XCAM_TEST_MAX_STR_SIZE, "orig_fisheye_%d_%d.jpg", frame_num, i); |
| ins[i]->cv_write_image (img_name, frame_str, idx_str); |
| } |
| |
| for (uint32_t i = 0; i < outs.size (); ++i) { |
| std::snprintf (img_name, XCAM_TEST_MAX_STR_SIZE, "%s_%d.jpg", outs[i]->get_file_name (), frame_num); |
| outs[i]->cv_write_image (img_name, frame_str); |
| } |
| frame_num++; |
| } |
| #endif |
| } |
| |
| static XCamReturn |
| ensure_output_format (const char *file_name, const SoftType &type, bool &nv12_output) |
| { |
| char suffix[XCAM_TEST_MAX_STR_SIZE] = {'\0'}; |
| const char *ptr = std::strrchr (file_name, '.'); |
| std::snprintf (suffix, XCAM_TEST_MAX_STR_SIZE, "%s", ptr + 1); |
| if (!strcasecmp (suffix, "mp4")) { |
| #if XCAM_TEST_OPENCV |
| if (type != SoftTypeStitch) { |
| XCAM_LOG_ERROR ("only stitch type supports MP4 output format"); |
| return XCAM_RETURN_ERROR_PARAM; |
| } |
| nv12_output = false; |
| #else |
| XCAM_LOG_ERROR ("only supports NV12 output format"); |
| return XCAM_RETURN_ERROR_PARAM; |
| #endif |
| } |
| |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| static bool |
| check_element (const SoftElements &elements, const uint32_t &idx) |
| { |
| if (idx >= elements.size ()) |
| return false; |
| |
| if (!elements[idx].ptr()) { |
| XCAM_LOG_ERROR ("SoftElement(idx:%d) ptr is NULL", idx); |
| return false; |
| } |
| |
| XCAM_FAIL_RETURN ( |
| ERROR, |
| elements[idx]->get_width () && elements[idx]->get_height (), |
| false, |
| "SoftElement(idx:%d): invalid parameters width:%d height:%d", |
| idx, elements[idx]->get_width (), elements[idx]->get_height ()); |
| |
| return true; |
| } |
| |
| static XCamReturn |
| check_elements (const SoftElements &elements) |
| { |
| for (uint32_t i = 0; i < elements.size (); ++i) { |
| XCAM_FAIL_RETURN ( |
| ERROR, |
| check_element (elements, i), |
| XCAM_RETURN_ERROR_PARAM, |
| "invalid SoftElement index:%d\n", i); |
| } |
| |
| return XCAM_RETURN_NO_ERROR; |
| } |
| |
| static XCamReturn |
| run_topview (const SmartPtr<Stitcher> &stitcher, const SoftElements &outs) |
| { |
| BowlModel bowl_model (stitcher->get_bowl_config (), outs[0]->get_width (), outs[0]->get_height ()); |
| return remap_topview_buf (bowl_model, outs[0]->get_buf (), outs[1]->get_buf (), |
| outs[1]->get_width (), outs[1]->get_height ()); |
| } |
| |
| static int |
| run_stitcher ( |
| const SmartPtr<Stitcher> &stitcher, |
| const SoftElements &ins, const SoftElements &outs, |
| bool nv12_output, bool save_output, int loop) |
| { |
| XCamReturn ret = XCAM_RETURN_NO_ERROR; |
| CHECK (check_elements (ins), "invalid input elements"); |
| CHECK (check_elements (outs), "invalid output elements"); |
| |
| VideoBufferList in_buffers; |
| while (loop--) { |
| for (uint32_t i = 0; i < ins.size (); ++i) { |
| CHECK (ins[i]->rewind_file (), "rewind buffer from file(%s) failed", ins[i]->get_file_name ()); |
| } |
| |
| do { |
| in_buffers.clear (); |
| |
| for (uint32_t i = 0; i < ins.size (); ++i) { |
| ret = ins[i]->read_buf(); |
| if (ret == XCAM_RETURN_BYPASS) |
| break; |
| CHECK (ret, "read buffer from file(%s) failed.", ins[i]->get_file_name ()); |
| |
| in_buffers.push_back (ins[i]->get_buf ()); |
| } |
| if (ret == XCAM_RETURN_BYPASS) |
| break; |
| |
| CHECK ( |
| stitcher->stitch_buffers (in_buffers, outs[0]->get_buf ()), |
| "stitch buffer failed."); |
| |
| if (save_output) { |
| if (check_element (outs, 1)) { |
| CHECK (run_topview (stitcher, outs), "run topview failed"); |
| } |
| |
| write_image (ins, outs, nv12_output); |
| } |
| |
| FPS_CALCULATION (soft - stitcher, XCAM_OBJ_DUR_FRAME_NUM); |
| } while (true); |
| } |
| |
| return 0; |
| } |
| |
| static void usage(const char* arg0) |
| { |
| printf ("Usage:\n" |
| "%s --type TYPE--input0 file0 --input1 file1 --output file\n" |
| "\t--type processing type, selected from: blend, remap, stitch, ...\n" |
| "\t-- [stitch]: read calibration files from exported path $FISHEYE_CONFIG_PATH\n" |
| "\t--input0 input image(NV12)\n" |
| "\t--input1 input image(NV12)\n" |
| "\t--input2 input image(NV12)\n" |
| "\t--input3 input image(NV12)\n" |
| "\t--output output image(NV12)\n" |
| "\t--in-w optional, input width, default: 1920\n" |
| "\t--in-h optional, input height, default: 1080\n" |
| "\t--out-w optional, output width, default: 1920\n" |
| "\t--out-h optional, output height, default: 960\n" |
| "\t--topview-w optional, output width, default: 1280\n" |
| "\t--topview-h optional, output height, default: 720\n" |
| "\t--save optional, save file or not, select from [true/false], default: true\n" |
| "\t--loop optional, how many loops need to run, default: 1\n" |
| "\t--help usage\n", |
| arg0); |
| } |
| |
| int main (int argc, char *argv[]) |
| { |
| uint32_t input_width = 1920; |
| uint32_t input_height = 1080; |
| uint32_t output_width = 1920; //output_height * 2; |
| uint32_t output_height = 960; //960; |
| uint32_t topview_width = 1280; |
| uint32_t topview_height = 720; |
| SoftType type = SoftTypeNone; |
| |
| SoftElements ins; |
| SoftElements outs; |
| |
| int loop = 1; |
| bool save_output = true; |
| bool nv12_output = true; |
| |
| const struct option long_opts[] = { |
| {"type", required_argument, NULL, 't'}, |
| {"input0", required_argument, NULL, 'i'}, |
| {"input1", required_argument, NULL, 'j'}, |
| {"input2", required_argument, NULL, 'k'}, |
| {"input3", required_argument, NULL, 'l'}, |
| {"output", required_argument, NULL, 'o'}, |
| {"in-w", required_argument, NULL, 'w'}, |
| {"in-h", required_argument, NULL, 'h'}, |
| {"out-w", required_argument, NULL, 'W'}, |
| {"out-h", required_argument, NULL, 'H'}, |
| {"topview-w", required_argument, NULL, 'P'}, |
| {"topview-h", required_argument, NULL, 'V'}, |
| {"save", required_argument, NULL, 's'}, |
| {"loop", required_argument, NULL, 'L'}, |
| {"help", no_argument, NULL, 'e'}, |
| {NULL, 0, NULL, 0}, |
| }; |
| |
| int opt = -1; |
| while ((opt = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { |
| switch (opt) { |
| case 't': |
| XCAM_ASSERT (optarg); |
| if (!strcasecmp (optarg, "blend")) |
| type = SoftTypeBlender; |
| else if (!strcasecmp (optarg, "remap")) |
| type = SoftTypeRemap; |
| else if (!strcasecmp (optarg, "stitch")) |
| type = SoftTypeStitch; |
| else { |
| XCAM_LOG_ERROR ("unknown type:%s", optarg); |
| usage (argv[0]); |
| return -1; |
| } |
| break; |
| |
| case 'i': |
| XCAM_ASSERT (optarg); |
| ADD_ENELEMT(ins, optarg); |
| break; |
| case 'j': |
| XCAM_ASSERT (optarg); |
| ADD_ENELEMT(ins, optarg); |
| break; |
| case 'k': |
| XCAM_ASSERT (optarg); |
| ADD_ENELEMT(ins, optarg); |
| break; |
| case 'l': |
| XCAM_ASSERT (optarg); |
| ADD_ENELEMT(ins, optarg); |
| break; |
| case 'o': |
| XCAM_ASSERT (optarg); |
| ADD_ENELEMT(outs, optarg); |
| break; |
| case 'w': |
| input_width = atoi(optarg); |
| break; |
| case 'h': |
| input_height = atoi(optarg); |
| break; |
| case 'W': |
| output_width = atoi(optarg); |
| break; |
| case 'H': |
| output_height = atoi(optarg); |
| break; |
| case 'P': |
| topview_width = atoi(optarg); |
| break; |
| case 'V': |
| topview_height = atoi(optarg); |
| break; |
| case 's': |
| save_output = (strcasecmp (optarg, "false") == 0 ? false : true); |
| break; |
| case 'L': |
| loop = atoi(optarg); |
| break; |
| default: |
| XCAM_LOG_ERROR ("getopt_long return unknown value:%c", opt); |
| usage (argv[0]); |
| return -1; |
| } |
| } |
| |
| if (optind < argc || argc < 2) { |
| XCAM_LOG_ERROR ("unknown option %s", argv[optind]); |
| usage (argv[0]); |
| return -1; |
| } |
| |
| if (SoftTypeNone == type) { |
| XCAM_LOG_ERROR ("Type was not set"); |
| usage (argv[0]); |
| return -1; |
| } |
| |
| if (ins.empty () || outs.empty () || |
| !strlen (ins[0]->get_file_name ()) || !strlen (outs[0]->get_file_name ())) { |
| XCAM_LOG_ERROR ("input or output file name was not set"); |
| usage (argv[0]); |
| return -1; |
| } |
| |
| for (uint32_t i = 0; i < ins.size (); ++i) { |
| printf ("input%d file:\t\t%s\n", i, ins[i]->get_file_name ()); |
| } |
| printf ("output file:\t\t%s\n", outs[0]->get_file_name ()); |
| printf ("input width:\t\t%d\n", input_width); |
| printf ("input height:\t\t%d\n", input_height); |
| printf ("output width:\t\t%d\n", output_width); |
| printf ("output height:\t\t%d\n", output_height); |
| printf ("topview width:\t\t%d\n", topview_width); |
| printf ("topview height:\t\t%d\n", topview_height); |
| printf ("save output:\t\t%s\n", save_output ? "true" : "false"); |
| printf ("loop count:\t\t%d\n", loop); |
| |
| VideoBufferInfo in_info, out_info; |
| in_info.init (V4L2_PIX_FMT_NV12, input_width, input_height); |
| out_info.init (V4L2_PIX_FMT_NV12, output_width, output_height); |
| |
| for (uint32_t i = 0; i < ins.size (); ++i) { |
| ins[i]->set_buf_size (input_width, input_height); |
| CHECK (ins[i]->create_buf_pool (in_info, 6), "create buffer pool failed"); |
| CHECK (ins[i]->open_file ("rb"), "open file(%s) failed", ins[i]->get_file_name ()); |
| } |
| |
| outs[0]->set_buf_size (output_width, output_height); |
| if (save_output) { |
| CHECK (ensure_output_format (outs[0]->get_file_name (), type, nv12_output), "unsupported output format"); |
| if (nv12_output) { |
| CHECK (outs[0]->open_file ("wb"), "open file(%s) failed", outs[0]->get_file_name ()); |
| } |
| } |
| |
| switch (type) { |
| case SoftTypeBlender: { |
| CHECK_EXP (ins.size () >= 2, "blender need 2 input files."); |
| SmartPtr<Blender> blender = Blender::create_soft_blender (); |
| XCAM_ASSERT (blender.ptr ()); |
| blender->set_output_size (output_width, output_height); |
| Rect merge_window; |
| merge_window.pos_x = 0; |
| merge_window.pos_y = 0; |
| merge_window.width = out_info.width; |
| merge_window.height = out_info.height; |
| blender->set_merge_window (merge_window); |
| |
| CHECK (ins[0]->read_buf(), "read buffer from file(%s) failed.", ins[0]->get_file_name ()); |
| CHECK (ins[1]->read_buf(), "read buffer from file(%s) failed.", ins[1]->get_file_name ()); |
| RUN_N (blender->blend (ins[0]->get_buf (), ins[1]->get_buf (), outs[0]->get_buf ()), loop, "blend buffer failed."); |
| if (save_output) |
| outs[0]->write_buf (); |
| break; |
| } |
| case SoftTypeRemap: { |
| SmartPtr<GeoMapper> mapper = GeoMapper::create_soft_geo_mapper (); |
| XCAM_ASSERT (mapper.ptr ()); |
| mapper->set_output_size (output_width, output_height); |
| mapper->set_lookup_table (map_table, MAP_WIDTH, MAP_HEIGHT); |
| //mapper->set_factors ((output_width - 1.0f) / (MAP_WIDTH - 1.0f), (output_height - 1.0f) / (MAP_HEIGHT - 1.0f)); |
| |
| CHECK (ins[0]->read_buf(), "read buffer from file(%s) failed.", ins[0]->get_file_name ()); |
| RUN_N (mapper->remap (ins[0]->get_buf (), outs[0]->get_buf ()), loop, "remap buffer failed."); |
| if (save_output) |
| outs[0]->write_buf (); |
| break; |
| } |
| case SoftTypeStitch: { |
| CHECK_EXP (ins.size () >= 2 && ins.size () <= 4, "stitcher need at 2~4 input files."); |
| |
| uint32_t camera_count = ins.size (); |
| SmartPtr<Stitcher> stitcher = Stitcher::create_soft_stitcher (); |
| XCAM_ASSERT (stitcher.ptr ()); |
| |
| CameraInfo cam_info[4]; |
| const char *fisheye_config_path = getenv ("FISHEYE_CONFIG_PATH"); |
| if (!fisheye_config_path) |
| fisheye_config_path = FISHEYE_CONFIG_PATH; |
| |
| for (uint32_t i = 0; i < camera_count; ++i) { |
| if (parse_camera_info (fisheye_config_path, i, cam_info[i], camera_count) != 0) { |
| XCAM_LOG_ERROR ("parse fisheye dewarp info(idx:%d) failed.", i); |
| return -1; |
| } |
| } |
| |
| PointFloat3 bowl_coord_offset; |
| if (camera_count == 4) { |
| centralize_bowl_coord_from_cameras ( |
| cam_info[0].calibration.extrinsic, cam_info[1].calibration.extrinsic, |
| cam_info[2].calibration.extrinsic, cam_info[3].calibration.extrinsic, |
| bowl_coord_offset); |
| } |
| |
| stitcher->set_camera_num (camera_count); |
| for (uint32_t i = 0; i < camera_count; ++i) { |
| stitcher->set_camera_info (i, cam_info[i]); |
| } |
| |
| BowlDataConfig bowl; |
| bowl.wall_height = 3000.0f; |
| bowl.ground_length = 2000.0f; |
| //bowl.a = 5000.0f; |
| //bowl.b = 3600.0f; |
| //bowl.c = 3000.0f; |
| bowl.angle_start = 0.0f; |
| bowl.angle_end = 360.0f; |
| stitcher->set_bowl_config (bowl); |
| stitcher->set_output_size (output_width, output_height); |
| |
| if (save_output) { |
| add_element (outs, "topview", topview_width, topview_height); |
| elements_open_file (outs, "wb", nv12_output); |
| } |
| CHECK_EXP ( |
| run_stitcher (stitcher, ins, outs, nv12_output, save_output, loop) == 0, |
| "run stitcher failed."); |
| break; |
| } |
| |
| default: { |
| XCAM_LOG_ERROR ("unsupported type:%d", type); |
| usage (argv[0]); |
| return -1; |
| } |
| } |
| |
| return 0; |
| } |