1 /* 2 * test-image-blend.cpp - test cl image 3 * 4 * Copyright (c) 2016 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 <unistd.h> 24 #include <getopt.h> 25 #include <ocl/cl_device.h> 26 #include <ocl/cl_context.h> 27 #include <ocl/cl_blender.h> 28 #include <image_file_handle.h> 29 #include <ocl/cl_geo_map_handler.h> 30 #if HAVE_LIBDRM 31 #include <drm_display.h> 32 #endif 33 #include <dma_video_buffer.h> 34 35 using namespace XCam; 36 37 #define ENABLE_DMA_TEST 0 38 39 static uint32_t input_format = V4L2_PIX_FMT_NV12; 40 //static uint32_t output_format = V4L2_PIX_FMT_NV12; 41 static uint32_t input_width0 = 1280, input_width1 = 1280; 42 static uint32_t input_height = 960; 43 static uint32_t output_width = 1920; 44 static uint32_t output_height; 45 static bool need_save_output = true; 46 static bool enable_geo = false; 47 static bool enable_seam = false; 48 49 static int loop = 0; 50 static uint32_t map_width = 51, map_height = 43; 51 static const char *map0 = "fisheye0.csv"; 52 static const char *map1 = "fisheye1.csv"; 53 static char file_in0_name[XCAM_MAX_STR_SIZE], file_in1_name[XCAM_MAX_STR_SIZE], file_out_name[XCAM_MAX_STR_SIZE]; 54 55 static int read_map_data (const char* file, GeoPos *map, int width, int height); 56 57 static void 58 usage(const char* arg0) 59 { 60 printf ("Usage:\n" 61 "%s --input0 file --input1 file --output file" 62 " [--input-w0 width] [--input-w1 width] [--input-h height] [--output-w width] \n" 63 "\t--input0, first image(NV12)\n" 64 "\t--input1, second image(NV12)\n" 65 "\t--output, output image(NV12) PREFIX\n" 66 "\t--input-w0, optional, input width; default:1280\n" 67 "\t--input-w1, optional, input width; default:1280\n" 68 "\t--input-h, optional, input height; default:960\n" 69 "\t--output-w, optional, output width; default:1920, output height is same as input height.\n" 70 "\t--loop, optional, how many loops need to run for performance test, default 0; \n" 71 "\t--save, optional, save file or not, default true; select from [true/false]\n" 72 "\t--enable-geo, optional, enable geo map image frist. default: no\n" 73 "\t--enable-seam, optional, enable seam finder in blending area. default: no\n" 74 "\t--help, usage\n", 75 arg0); 76 } 77 78 static int 79 geo_correct_image ( 80 SmartPtr<CLGeoMapHandler> geo_map_handler, SmartPtr<VideoBuffer> &in_out, 81 GeoPos *geo_map0, uint32_t map_width, uint32_t map_height, 82 char *file_name, bool need_save_output) 83 { 84 XCamReturn ret = XCAM_RETURN_NO_ERROR; 85 SmartPtr<VideoBuffer> geo_out; 86 geo_map_handler->set_map_data (geo_map0, map_width, map_height); 87 ret = geo_map_handler->execute (in_out, geo_out); 88 CHECK (ret, "geo map handler execute inpu0 failed"); 89 XCAM_ASSERT (geo_out.ptr ()); 90 in_out = geo_out; 91 92 if (need_save_output) { 93 char gdc_dump_name[1024]; 94 snprintf (gdc_dump_name, 1024, "gdc-%s", file_name); 95 ImageFileHandle file_out; 96 file_out.open (gdc_dump_name, "wb"); 97 file_out.write_buf (geo_out); 98 file_out.close (); 99 printf ("write gdc output buffer to: %s done\n", gdc_dump_name); 100 } 101 return 0; 102 } 103 104 #if (ENABLE_DMA_TEST) && (HAVE_LIBDRM) 105 static SmartPtr<VideoBuffer> 106 dma_buf_to_xcam_buf ( 107 SmartPtr<DrmDisplay> display, int dma_fd, 108 uint32_t width, uint32_t height, uint32_t size, 109 uint32_t aligned_width = 0, uint32_t aligned_height = 0) 110 { 111 /* 112 * 113 * XCAM_ASSERT (native_handle_t.numFds == 1); 114 * XCAM_ASSERT (native_handle_t.data[0] > 0); 115 * dma_fd = native_handle_t.data[0] ; 116 */; 117 VideoBufferInfo info; 118 SmartPtr<VideoBuffer> dma_buf; 119 SmartPtr<VideoBuffer> output; 120 121 XCAM_ASSERT (dma_fd > 0); 122 123 if (aligned_width == 0) 124 aligned_width = XCAM_ALIGN_UP(width, 16); 125 if (aligned_height == 0) 126 aligned_height = XCAM_ALIGN_UP(height, 16); 127 128 info.init (V4L2_PIX_FMT_NV12, width, height, aligned_width, aligned_height, size); 129 dma_buf = new DmaVideoBuffer (info, dma_fd); 130 output = display->convert_to_drm_bo_buf (display, dma_buf); 131 if (!output.ptr ()) { 132 XCAM_LOG_ERROR ("dma_buf(%d) convert to xcam_buf failed", dma_fd); 133 } 134 135 return output; 136 } 137 138 static SmartPtr<VideoBuffer> 139 create_dma_buffer (SmartPtr<DrmDisplay> &display, const VideoBufferInfo &info) 140 { 141 SmartPtr<BufferPool> buf_pool = new DrmBoBufferPool (display); 142 buf_pool->set_video_info (info); 143 buf_pool->reserve (1); 144 return buf_pool->get_buffer (buf_pool); 145 } 146 #endif 147 148 static XCamReturn 149 blend_images ( 150 SmartPtr<VideoBuffer> input0, SmartPtr<VideoBuffer> input1, 151 SmartPtr<VideoBuffer> &output_buf, 152 SmartPtr<CLBlender> blender) 153 { 154 blender->set_output_size (output_width, output_height); 155 input0->attach_buffer (input1); 156 return blender->execute (input0, output_buf); 157 } 158 159 int main (int argc, char *argv[]) 160 { 161 GeoPos *geo_map0 = NULL, *geo_map1 = NULL; 162 XCamReturn ret = XCAM_RETURN_NO_ERROR; 163 SmartPtr<CLImageHandler> image_handler; 164 SmartPtr<CLGeoMapHandler> geo_map_handler; 165 SmartPtr<CLBlender> blender; 166 VideoBufferInfo input_buf_info0, input_buf_info1, output_buf_info; 167 SmartPtr<CLContext> context; 168 SmartPtr<BufferPool> buf_pool0, buf_pool1; 169 ImageFileHandle file_in0, file_in1, file_out; 170 SmartPtr<VideoBuffer> input0, input1; 171 SmartPtr<VideoBuffer> output_buf; 172 SmartPtr<VideoBuffer> read_buf; 173 174 #define FAILED_GEO_FREE { delete [] geo_map0; delete [] geo_map1; return -1; } 175 176 const struct option long_opts[] = { 177 {"input0", required_argument, NULL, 'i'}, 178 {"input1", required_argument, NULL, 'I'}, 179 {"output", required_argument, NULL, 'o'}, 180 {"input-w0", required_argument, NULL, 'w'}, 181 {"input-w1", required_argument, NULL, 'W'}, 182 {"input-h", required_argument, NULL, 'H'}, 183 {"output-w", required_argument, NULL, 'x'}, 184 {"loop", required_argument, NULL, 'l'}, 185 {"save", required_argument, NULL, 's'}, 186 {"enable-geo", no_argument, NULL, 'g'}, 187 {"enable-seam", no_argument, NULL, 'm'}, 188 {"help", no_argument, NULL, 'h'}, 189 {0, 0, 0, 0}, 190 }; 191 192 int opt = -1; 193 while ((opt = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { 194 switch (opt) { 195 case 'i': 196 strncpy (file_in0_name, optarg, XCAM_MAX_STR_SIZE); 197 break; 198 case 'I': 199 strncpy (file_in1_name, optarg, XCAM_MAX_STR_SIZE); 200 break; 201 case 'o': 202 strncpy (file_out_name, optarg, XCAM_MAX_STR_SIZE); 203 break; 204 case 'w': 205 input_width0 = atoi(optarg); 206 break; 207 case 'W': 208 input_width1 = atoi(optarg); 209 break; 210 case 'H': 211 input_height = atoi(optarg); 212 break; 213 case 'x': 214 output_width = atoi(optarg); 215 break; 216 case 'l': 217 loop = atoi(optarg); 218 break; 219 case 's': 220 need_save_output = (strcasecmp (optarg, "false") == 0 ? false : true); 221 break; 222 case 'g': 223 enable_geo = true; 224 break; 225 case 'm': 226 enable_seam = true; 227 break; 228 case 'h': 229 usage (argv[0]); 230 return -1; 231 default: 232 printf ("getopt_long return unknown value:%c\n", opt); 233 usage (argv[0]); 234 return -1; 235 236 } 237 } 238 239 if (optind < argc || argc < 2) { 240 printf("unknown option %s\n", argv[optind]); 241 usage (argv[0]); 242 return -1; 243 } 244 245 printf ("Description-----------\n"); 246 printf ("input0 file:%s\n", file_in0_name); 247 printf ("input1 file:%s\n", file_in1_name); 248 printf ("output file PREFIX:%s\n", file_out_name); 249 printf ("input0 width:%d\n", input_width0); 250 printf ("input1 width:%d\n", input_width1); 251 printf ("input/output height:%d\n", input_height); 252 printf ("output width:%d\n", output_width); 253 printf ("loop count:%d\n", loop); 254 printf ("need save file:%s\n", need_save_output ? "true" : "false"); 255 printf ("enable seam mask:%s\n", (enable_seam ? "true" : "false")); 256 printf ("----------------------\n"); 257 258 output_height = input_height; 259 input_buf_info0.init (input_format, input_width0, input_height); 260 input_buf_info1.init (input_format, input_width1, input_height); 261 output_buf_info.init (input_format, output_width, output_height); 262 #if (ENABLE_DMA_TEST) && (HAVE_LIBDRM) 263 SmartPtr<DrmDisplay> display = DrmDisplay::instance (); 264 buf_pool0 = new DrmBoBufferPool (display); 265 buf_pool1 = new DrmBoBufferPool (display); 266 #else 267 buf_pool0 = new CLVideoBufferPool (); 268 buf_pool1 = new CLVideoBufferPool (); 269 #endif 270 XCAM_ASSERT (buf_pool0.ptr () && buf_pool1.ptr ()); 271 buf_pool0->set_video_info (input_buf_info0); 272 buf_pool1->set_video_info (input_buf_info1); 273 if (!buf_pool0->reserve (2)) { 274 XCAM_LOG_ERROR ("init buffer pool failed"); 275 return -1; 276 } 277 if (!buf_pool1->reserve (2)) { 278 XCAM_LOG_ERROR ("init buffer pool failed"); 279 return -1; 280 } 281 282 context = CLDevice::instance ()->get_context (); 283 blender = create_pyramid_blender (context, 2, true, enable_seam).dynamic_cast_ptr<CLBlender> (); 284 XCAM_ASSERT (blender.ptr ()); 285 286 #if (ENABLE_DMA_TEST) && (HAVE_LIBDRM) 287 int dma_fd0 = 30, dma_fd1 = 31, dma_fd_out = 32; 288 input_buf_info0.init ( 289 input_format, input_width0, input_height, XCAM_ALIGN_UP (input_width0, 16), XCAM_ALIGN_UP(input_height, 16)); 290 input_buf_info1.init ( 291 input_format, input_width1, input_height, XCAM_ALIGN_UP (input_width1, 16), XCAM_ALIGN_UP(input_height, 16)); 292 output_buf_info.init ( 293 input_format, output_width, output_height, XCAM_ALIGN_UP (output_width, 16), XCAM_ALIGN_UP(output_height, 16)); 294 uint32_t in_size = input_buf_info0.aligned_width * input_buf_info0.aligned_height * 3 / 2; 295 uint32_t out_size = output_buf_info.aligned_width * output_buf_info.aligned_height * 3 / 2; 296 /* create dma fd, for buffer_handle_t just skip this segment, directly goto dma_buf_to_xcam_buf */ 297 SmartPtr<VideoBuffer> dma_buf0, dma_buf1, dma_buf_out; 298 dma_buf0 = create_dma_buffer (display, input_buf_info0); //unit test 299 dma_buf1 = create_dma_buffer (display, input_buf_info1); //unit test 300 dma_buf_out = create_dma_buffer (display, output_buf_info); //unit test 301 dma_fd0 = dma_buf0->get_fd (); //unit test 302 dma_fd1 = dma_buf1->get_fd (); //unit test 303 dma_fd_out = dma_buf_out->get_fd (); //unit test 304 /* 305 buffer_handle_t just go to here, 306 dma_fd0 = native_handle_t.data[0]; 307 dma_fd1 = native_handle_t.data[0]; 308 dma_fd_out = native_handle_t.data[0]; 309 */ 310 printf ("DMA handles, buf0:%d, buf1:%d, buf_out:%d\n", dma_fd0, dma_fd1, dma_fd_out); 311 input0 = dma_buf_to_xcam_buf ( 312 display, dma_fd0, input_width0, input_height, in_size, 313 input_buf_info0.aligned_width, input_buf_info0.aligned_height); 314 input1 = dma_buf_to_xcam_buf ( 315 display, dma_fd1, input_width0, input_height, in_size, 316 input_buf_info1.aligned_width, input_buf_info1.aligned_height); 317 output_buf = dma_buf_to_xcam_buf ( 318 display, dma_fd_out, output_width, output_height, out_size, 319 output_buf_info.aligned_width, output_buf_info.aligned_height); 320 blender->disable_buf_pool (true); 321 #else 322 input0 = buf_pool0->get_buffer (buf_pool0); 323 input1 = buf_pool1->get_buffer (buf_pool1); 324 XCAM_ASSERT (input0.ptr () && input1.ptr ()); 325 #endif 326 // 327 ret = file_in0.open (file_in0_name, "rb"); 328 CHECK_STATEMENT (ret, FAILED_GEO_FREE, "open input file(%s) failed", file_in0_name); 329 read_buf = input0; 330 ret = file_in0.read_buf (read_buf); 331 CHECK_STATEMENT (ret, FAILED_GEO_FREE, "read buffer0 from (%s) failed", file_in0_name); 332 333 ret = file_in1.open (file_in1_name, "rb"); 334 CHECK_STATEMENT (ret, FAILED_GEO_FREE, "open input file(%s) failed", file_in1_name); 335 read_buf = input1; 336 ret = file_in1.read_buf (read_buf); 337 CHECK_STATEMENT (ret, FAILED_GEO_FREE, "read buffer1 from (%s) failed", file_in1_name); 338 339 if (enable_geo) { 340 geo_map_handler = create_geo_map_handler (context).dynamic_cast_ptr<CLGeoMapHandler> (); 341 XCAM_ASSERT (geo_map_handler.ptr ()); 342 343 geo_map0 = new GeoPos[map_width * map_height]; 344 geo_map1 = new GeoPos[map_width * map_height]; 345 XCAM_ASSERT (geo_map0 && geo_map1); 346 if (read_map_data (map0, geo_map0, map_width, map_height) <= 0 || 347 read_map_data (map1, geo_map1, map_width, map_height) <= 0) { 348 delete [] geo_map0; 349 delete [] geo_map1; 350 return -1; 351 } 352 353 geo_map_handler->set_map_uint (28.0f, 28.0f); 354 } 355 356 int i = 0; 357 do { 358 input0->clear_attached_buffers (); 359 input1->clear_attached_buffers (); 360 361 if (enable_geo) { 362 geo_correct_image (geo_map_handler, input0, geo_map0, map_width, map_height, file_in0_name, need_save_output); 363 geo_correct_image (geo_map_handler, input1, geo_map1, map_width, map_height, file_in1_name, need_save_output); 364 } 365 366 ret = blend_images (input0, input1, output_buf, blender); 367 CHECK_STATEMENT (ret, FAILED_GEO_FREE, "blend_images execute failed"); 368 //printf ("DMA handles, output_buf:%d\n", output_buf->get_fd ()); 369 370 if (need_save_output) { 371 char out_name[1024]; 372 snprintf (out_name, 1023, "%s.%02d", file_out_name, i); 373 374 ret = file_out.open (out_name, "wb"); 375 CHECK_STATEMENT (ret, FAILED_GEO_FREE, "open output file(%s) failed", out_name); 376 ret = file_out.write_buf (output_buf); 377 CHECK_STATEMENT (ret, FAILED_GEO_FREE, "write buffer to (%s) failed", out_name); 378 printf ("write output buffer to: %s done\n", out_name); 379 } else { 380 // check info 381 ensure_gpu_buffer_done (output_buf); 382 } 383 384 FPS_CALCULATION (image_blend, XCAM_OBJ_DUR_FRAME_NUM); 385 ++i; 386 } while (i < loop); 387 388 delete [] geo_map0; 389 delete [] geo_map1; 390 391 return ret; 392 } 393 394 //return count 395 int read_map_data (const char* file, GeoPos *map, int width, int height) 396 { 397 char *ptr = NULL; 398 FILE *p_f = fopen (file, "rb"); 399 CHECK_EXP (p_f, "open geo-map file(%s) failed", file); 400 401 #define FAILED_READ_MAP { if (p_f) fclose(p_f); if (ptr) xcam_free (ptr); return -1; } 402 403 CHECK_DECLARE (ERROR, fseek(p_f, 0L, SEEK_END) == 0, FAILED_READ_MAP, "seek to file(%s) end failed", file); 404 size_t size = ftell (p_f); 405 XCAM_ASSERT ((int)size != -1); 406 fseek (p_f, 0L, SEEK_SET); 407 408 ptr = (char*)xcam_malloc (size + 1); 409 XCAM_ASSERT (ptr); 410 CHECK_DECLARE (ERROR, fread (ptr, 1, size, p_f) == size, FAILED_READ_MAP, "read map file(%s)failed", file); 411 ptr[size] = 0; 412 fclose (p_f); 413 p_f = NULL; 414 415 char *str_num = NULL; 416 char tokens[] = "\t ,\r\n"; 417 str_num = strtok (ptr, tokens); 418 int count = 0; 419 int x = 0, y = 0; 420 while (str_num != NULL) { 421 float num = strtof (str_num, NULL); 422 //printf ("%.3f\n", num); 423 424 x = count % width; 425 y = count / (width * 2); // x,y 426 if (y >= height) 427 break; 428 429 if (count % (width * 2) >= width) 430 map[y * width + x].y = num; 431 else 432 map[y * width + x].x = num; 433 434 ++count; 435 str_num = strtok (NULL, tokens); 436 } 437 xcam_free (ptr); 438 ptr = NULL; 439 CHECK_EXP (y < height, "map data(%s) count larger than expected(%dx%dx2)", file, width, height); 440 CHECK_EXP (count >= width * height * 2, "map data(%s) count less than expected(%dx%dx2)", file, width, height); 441 442 printf ("read map(%s) x/y data count:%d\n", file, count); 443 return count; 444 } 445 446