1/* 2 * cl_utils.cpp - CL Utilities 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@intel.com> 19 */ 20 21#include "cl_utils.h" 22#include "image_file_handle.h" 23#if HAVE_LIBDRM 24#include "intel/cl_intel_context.h" 25#include "intel/cl_va_memory.h" 26#endif 27 28namespace XCam { 29 30struct NV12Pixel { 31 float x_pos; 32 float y_pos; 33 34 float y; 35 float u; 36 float v; 37 38 NV12Pixel () 39 : x_pos (0.0f), y_pos (0.0f) 40 , y (0.0f), u (0.0f), v (0.0f) 41 {} 42}; 43 44static inline void 45clamp (float &value, float min, float max) 46{ 47 value = (value < min) ? min : ((value > max) ? max : value); 48} 49 50bool 51dump_image (SmartPtr<CLImage> image, const char *file_name) 52{ 53 XCAM_ASSERT (file_name); 54 55 const CLImageDesc &desc = image->get_image_desc (); 56 void *ptr = NULL; 57 size_t origin[3] = {0, 0, 0}; 58 size_t region[3] = {desc.width, desc.height, 1}; 59 size_t row_pitch; 60 size_t slice_pitch; 61 62 XCamReturn ret = image->enqueue_map (ptr, origin, region, &row_pitch, &slice_pitch, CL_MAP_READ); 63 XCAM_FAIL_RETURN (ERROR, xcam_ret_is_ok (ret), false, "dump image failed in enqueue_map"); 64 XCAM_ASSERT (ptr); 65 XCAM_ASSERT (row_pitch == desc.row_pitch); 66 uint8_t *buf_start = (uint8_t *)ptr; 67 uint32_t width = image->get_pixel_bytes () * desc.width; 68 69 FILE *fp = fopen (file_name, "wb"); 70 XCAM_FAIL_RETURN (ERROR, fp, false, "open file(%s) failed", file_name); 71 72 for (uint32_t i = 0; i < desc.height; ++i) { 73 uint8_t *buf_line = buf_start + row_pitch * i; 74 fwrite (buf_line, width, 1, fp); 75 } 76 image->enqueue_unmap (ptr); 77 fclose (fp); 78 XCAM_LOG_INFO ("write image:%s\n", file_name); 79 return true; 80} 81 82SmartPtr<CLBuffer> 83convert_to_clbuffer ( 84 const SmartPtr<CLContext> &context, 85 const SmartPtr<VideoBuffer> &buf) 86{ 87 SmartPtr<CLBuffer> cl_buf; 88 89 SmartPtr<CLVideoBuffer> cl_video_buf = buf.dynamic_cast_ptr<CLVideoBuffer> (); 90 if (cl_video_buf.ptr ()) { 91 cl_buf = cl_video_buf; 92 } 93#if HAVE_LIBDRM 94 else { 95 SmartPtr<DrmBoBuffer> bo_buf = buf.dynamic_cast_ptr<DrmBoBuffer> (); 96 SmartPtr<CLIntelContext> ctx = context.dynamic_cast_ptr<CLIntelContext> (); 97 XCAM_ASSERT (bo_buf.ptr () && ctx.ptr ()); 98 99 cl_buf = new CLVaBuffer (ctx, bo_buf); 100 } 101#else 102 XCAM_UNUSED (context); 103#endif 104 105 XCAM_FAIL_RETURN (WARNING, cl_buf.ptr (), NULL, "convert to clbuffer failed"); 106 return cl_buf; 107} 108 109SmartPtr<CLImage> 110convert_to_climage ( 111 const SmartPtr<CLContext> &context, 112 SmartPtr<VideoBuffer> &buf, 113 const CLImageDesc &desc, 114 uint32_t offset, 115 cl_mem_flags flags) 116{ 117 SmartPtr<CLImage> cl_image; 118 119 SmartPtr<CLVideoBuffer> cl_video_buf = buf.dynamic_cast_ptr<CLVideoBuffer> (); 120 if (cl_video_buf.ptr ()) { 121 SmartPtr<CLBuffer> cl_buf; 122 123 if (offset == 0) { 124 cl_buf = cl_video_buf; 125 } else { 126 uint32_t row_pitch = CLImage::calculate_pixel_bytes (desc.format) * 127 XCAM_ALIGN_UP (desc.width, XCAM_CL_IMAGE_ALIGNMENT_X); 128 uint32_t size = row_pitch * desc.height; 129 130 cl_buf = new CLSubBuffer (context, cl_video_buf, flags, offset, size); 131 } 132 133 cl_image = new CLImage2D (context, desc, flags, cl_buf); 134 } 135#if HAVE_LIBDRM 136 else { 137 SmartPtr<DrmBoBuffer> bo_buf = buf.dynamic_cast_ptr<DrmBoBuffer> (); 138 SmartPtr<CLIntelContext> ctx = context.dynamic_cast_ptr<CLIntelContext> (); 139 XCAM_ASSERT (bo_buf.ptr () && ctx.ptr ()); 140 141 cl_image = new CLVaImage (ctx, bo_buf, desc, offset); 142 } 143#endif 144 145 XCAM_FAIL_RETURN (WARNING, cl_image.ptr (), NULL, "convert to climage failed"); 146 return cl_image; 147} 148 149XCamReturn 150convert_nv12_mem_to_video_buffer ( 151 void *nv12_mem, uint32_t width, uint32_t height, uint32_t row_pitch, uint32_t offset_uv, 152 SmartPtr<VideoBuffer> &buf) 153{ 154 XCAM_ASSERT (nv12_mem); 155 XCAM_ASSERT (row_pitch >= width); 156 157 VideoBufferPlanarInfo planar; 158 const VideoBufferInfo info = buf->get_video_info (); 159 XCAM_FAIL_RETURN ( 160 DEBUG, (width == info.width) && (height == info.height), XCAM_RETURN_ERROR_PARAM, 161 "convert mem to video buffer failed since image sizes are not matched."); 162 163 uint8_t *out_mem = buf->map (); 164 XCAM_FAIL_RETURN (ERROR, out_mem, XCAM_RETURN_ERROR_MEM, "map buffer failed"); 165 166 uint8_t *src = (uint8_t *)nv12_mem; 167 uint8_t *dest = NULL; 168 for (uint32_t index = 0; index < info.components; index++) { 169 info.get_planar_info (planar, index); 170 171 dest = out_mem + info.offsets[index]; 172 for (uint32_t i = 0; i < planar.height; i++) { 173 memcpy (dest, src, width); 174 src += row_pitch; 175 dest += info.strides[index]; 176 } 177 178 src = (uint8_t *)nv12_mem + offset_uv; 179 } 180 181 buf->unmap (); 182 return XCAM_RETURN_NO_ERROR; 183} 184 185XCamReturn 186interpolate_pixel_value ( 187 uint8_t* stitch_mem, 188 float image_coord_x, float image_coord_y, 189 float &y, float &u, float &v, 190 const VideoBufferInfo& stitch_info) 191{ 192 XCAM_ASSERT (image_coord_y < stitch_info.height && image_coord_x < stitch_info.width); 193 194 uint8_t y00, y01, y10, y11; 195 uint8_t u00, u01, u10, u11; 196 uint8_t v00, v01, v10, v11; 197 198 uint32_t x0 = (uint32_t) image_coord_x; 199 uint32_t x1 = (x0 < stitch_info.width - 1) ? (x0 + 1) : x0; 200 uint32_t y0 = (uint32_t) image_coord_y; 201 uint32_t y1 = (y0 < stitch_info.height - 1) ? (y0 + 1) : y0; 202 203 float rate00 = (x0 + 1 - image_coord_x) * (y0 + 1 - image_coord_y); 204 float rate01 = (x0 + 1 - image_coord_x) * (image_coord_y - y0); 205 float rate10 = (image_coord_x - x0) * (y0 + 1 - image_coord_y); 206 float rate11 = (image_coord_x - x0) * (image_coord_y - y0); 207 208 y00 = stitch_mem[y0 * stitch_info.strides[0] + x0]; 209 y01 = stitch_mem[y1 * stitch_info.strides[0] + x0]; 210 y10 = stitch_mem[y0 * stitch_info.strides[0] + x1]; 211 y11 = stitch_mem[y1 * stitch_info.strides[0] + x1]; 212 213 u00 = stitch_mem[stitch_info.offsets[1] + y0 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x0, 2)]; 214 u01 = stitch_mem[stitch_info.offsets[1] + y1 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x0, 2)]; 215 u10 = stitch_mem[stitch_info.offsets[1] + y0 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x1, 2)]; 216 u11 = stitch_mem[stitch_info.offsets[1] + y1 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x1, 2)]; 217 218 v00 = stitch_mem[stitch_info.offsets[1] + y0 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x0, 2) + 1]; 219 v01 = stitch_mem[stitch_info.offsets[1] + y1 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x0, 2) + 1]; 220 v10 = stitch_mem[stitch_info.offsets[1] + y0 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x1, 2) + 1]; 221 v11 = stitch_mem[stitch_info.offsets[1] + y1 / 2 * stitch_info.strides[1] + XCAM_ALIGN_DOWN (x1, 2) + 1]; 222 223 y = y00 * rate00 + y01 * rate01 + y10 * rate10 + y11 * rate11; 224 u = u00 * rate00 + u01 * rate01 + u10 * rate10 + u11 * rate11; 225 v = v00 * rate00 + v01 * rate01 + v10 * rate10 + v11 * rate11; 226 227 return XCAM_RETURN_NO_ERROR; 228} 229 230XCamReturn 231map_to_specific_view ( 232 uint8_t *specific_view_mem, uint8_t* stitch_mem, 233 uint32_t row, uint32_t col, 234 float image_coord_x, float image_coord_y, 235 const VideoBufferInfo& specific_view_info, const VideoBufferInfo& stitch_info) 236{ 237 XCAM_ASSERT (row < specific_view_info.height && col < specific_view_info.width); 238 239 float y, u, v; 240 241 interpolate_pixel_value (stitch_mem, image_coord_x, image_coord_y, y, u, v, stitch_info); 242 243 uint32_t y_index = row * specific_view_info.strides[0] + col; 244 uint32_t u_index = specific_view_info.offsets[1] + row / 2 * specific_view_info.strides[1] + XCAM_ALIGN_DOWN (col, 2); 245 246 specific_view_mem[y_index] = (uint8_t)y; 247 specific_view_mem[u_index] = (uint8_t)u; 248 specific_view_mem[u_index + 1] = (uint8_t)v; 249 250 return XCAM_RETURN_NO_ERROR; 251} 252 253XCamReturn 254generate_topview_map_table ( 255 const VideoBufferInfo &stitch_info, 256 const BowlDataConfig &config, 257 std::vector<PointFloat2> &map_table, 258 int width, int height) 259{ 260 int center_x = width / 2; 261 int center_y = height / 2; 262 263 float show_width_mm = 5000.0f; 264 float length_per_pixel = show_width_mm / height; 265 266 map_table.resize (height * width); 267 268 for(int row = 0; row < height; row++) { 269 for(int col = 0; col < width; col++) { 270 PointFloat3 world; 271 world.x = (col - center_x) * length_per_pixel; 272 world.y = (center_y - row) * length_per_pixel; 273 world.z = 0.0f; 274 275 PointFloat2 image_pos = 276 bowl_view_coords_to_image (config, world, stitch_info.width, stitch_info.height); 277 278 map_table[row * width + col] = image_pos; 279 } 280 } 281 282 return XCAM_RETURN_NO_ERROR; 283} 284 285XCamReturn 286generate_rectifiedview_map_table ( 287 const VideoBufferInfo &stitch_info, 288 const BowlDataConfig &config, 289 std::vector<PointFloat2> &map_table, 290 float angle_start, float angle_end, 291 int width, int height) 292{ 293 float center_x = width / 2; 294 295 float focal_plane_dist = 6000.0f; 296 297 float angle_center = (angle_start + angle_end) / 2.0f; 298 float theta = degree2radian((angle_end - angle_start)) / 2.0f; 299 float length_per_pixel_x = 2 * focal_plane_dist * tan (theta) / width; 300 301 float fov_up = degree2radian (20.0f); 302 float fov_down = degree2radian (35.0f); 303 304 float length_per_pixel_y = (focal_plane_dist * tan (fov_up) + focal_plane_dist * tan (fov_down)) / height; 305 306 float center_y = tan (fov_up) / (tan (fov_up) + tan (fov_down)) * height; 307 308 PointFloat3 world_pos; 309 float plane_center_coords[3]; 310 311 plane_center_coords[0] = focal_plane_dist * cos (degree2radian (angle_center)); 312 plane_center_coords[1] = -focal_plane_dist * sin (degree2radian (angle_center)); 313 plane_center_coords[2] = 0.0f; 314 315 map_table.resize (width * height); 316 317 for (int row = 0; row < height; row++) { 318 for (int col = 0; col < width; col++) { 319 float plane_point_coords[3]; 320 plane_point_coords[0] = (center_x - col) * length_per_pixel_x * cos (PI / 2 - degree2radian (angle_center)) + plane_center_coords[0]; 321 plane_point_coords[1] = (center_x - col) * length_per_pixel_x * sin (PI / 2 - degree2radian (angle_center)) + plane_center_coords[1]; 322 plane_point_coords[2] = (center_y - row) * length_per_pixel_y + plane_center_coords[2]; 323 324 float rate_xz, rate_yz; 325 if (XCAM_DOUBLE_EQUAL_AROUND (plane_point_coords[2], 0.0f) && XCAM_DOUBLE_EQUAL_AROUND (plane_point_coords[1], 0.0f)) { 326 world_pos.x = config.a; 327 world_pos.y = 0; 328 world_pos.z = 0; 329 } else if (XCAM_DOUBLE_EQUAL_AROUND (plane_point_coords[2], 0.0f)) { 330 world_pos.z = 0.0f; 331 332 float rate_xy = plane_point_coords[0] / plane_point_coords[1]; 333 float square_y = 1 / (rate_xy * rate_xy / (config.a * config.a) + 1 / (config.b * config.b)); 334 world_pos.y = (plane_point_coords[1] > 0) ? sqrt (square_y) : -sqrt (square_y); 335 world_pos.x = rate_xy * world_pos.y; 336 } else { 337 rate_xz = plane_point_coords[0] / plane_point_coords[2]; 338 rate_yz = plane_point_coords[1] / plane_point_coords[2]; 339 340 float square_z = 1 / (rate_xz * rate_xz / (config.a * config.a) + rate_yz * rate_yz / (config.b * config.b) + 1 / (config.c * config.c)); 341 world_pos.z = (plane_point_coords[2] > 0) ? sqrt (square_z) : -sqrt (square_z); 342 world_pos.z = (world_pos.z <= -config.center_z) ? -config.center_z : world_pos.z; 343 world_pos.x = rate_xz * world_pos.z; 344 world_pos.y = rate_yz * world_pos.z; 345 } 346 347 world_pos.z += config.center_z; 348 349 PointFloat2 image_coord = 350 bowl_view_coords_to_image (config, world_pos, stitch_info.width, stitch_info.height); 351 352 map_table[row * width + col] = image_coord; 353 } 354 } 355 356 return XCAM_RETURN_NO_ERROR; 357} 358 359XCamReturn 360sample_generate_top_view ( 361 SmartPtr<VideoBuffer> &stitch_buf, 362 SmartPtr<VideoBuffer> top_view_buf, 363 const BowlDataConfig &config, 364 std::vector<PointFloat2> &map_table) 365{ 366 const VideoBufferInfo top_view_info = top_view_buf->get_video_info (); 367 const VideoBufferInfo stitch_info = stitch_buf->get_video_info (); 368 369 int top_view_resolution_w = top_view_buf->get_video_info ().width; 370 int top_view_resolution_h = top_view_buf->get_video_info ().height; 371 372 if((int)map_table.size () != top_view_resolution_w * top_view_resolution_h) { 373 map_table.clear (); 374 generate_topview_map_table (stitch_info, config, map_table, top_view_resolution_w, top_view_resolution_h); 375 } 376 377 uint8_t *top_view_mem = NULL; 378 uint8_t *stitch_mem = NULL; 379 top_view_mem = top_view_buf->map (); 380 stitch_mem = stitch_buf->map (); 381 382 for(int row = 0; row < top_view_resolution_h; row++) { 383 for(int col = 0; col < top_view_resolution_w; col++) { 384 PointFloat2 image_coord = map_table[row * top_view_resolution_w + col]; 385 386 map_to_specific_view (top_view_mem, stitch_mem, row, col, image_coord.x, image_coord.y, top_view_info, stitch_info); 387 } 388 } 389 390 top_view_buf->unmap(); 391 stitch_buf->unmap(); 392 393 return XCAM_RETURN_NO_ERROR; 394} 395 396XCamReturn 397sample_generate_rectified_view ( 398 SmartPtr<VideoBuffer> &stitch_buf, 399 SmartPtr<VideoBuffer> rectified_view_buf, 400 const BowlDataConfig &config, 401 float angle_start, float angle_end, 402 std::vector<PointFloat2> &map_table) 403{ 404 const VideoBufferInfo rectified_view_info = rectified_view_buf->get_video_info (); 405 const VideoBufferInfo stitch_info = stitch_buf->get_video_info (); 406 407 int rectified_view_resolution_w = rectified_view_buf->get_video_info ().width; 408 int rectified_view_resolution_h = rectified_view_buf->get_video_info ().height; 409 410 if((int)map_table.size () != rectified_view_resolution_w * rectified_view_resolution_h) { 411 map_table.clear (); 412 generate_rectifiedview_map_table (stitch_info, config, map_table, angle_start, angle_end, rectified_view_resolution_w, rectified_view_resolution_h); 413 } 414 415 uint8_t *rectified_view_mem = NULL; 416 uint8_t *stitch_mem = NULL; 417 rectified_view_mem = rectified_view_buf->map (); 418 stitch_mem = stitch_buf->map (); 419 420 for(int row = 0; row < rectified_view_resolution_h; row++) { 421 for(int col = 0; col < rectified_view_resolution_w; col++) { 422 PointFloat2 image_coord = map_table[row * rectified_view_resolution_w + col]; 423 424 map_to_specific_view (rectified_view_mem, stitch_mem, row, col, image_coord.x, image_coord.y, rectified_view_info, stitch_info); 425 } 426 } 427 428 rectified_view_buf->unmap(); 429 stitch_buf->unmap(); 430 431 return XCAM_RETURN_NO_ERROR; 432} 433 434} 435