1 /* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. 2 * 3 * Redistribution and use in source and binary forms, with or without 4 * modification, are permitted provided that the following conditions are 5 * met: 6 * * Redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * * Redistributions in binary form must reproduce the above 9 * copyright notice, this list of conditions and the following 10 * disclaimer in the documentation and/or other materials provided 11 * with the distribution. 12 * * Neither the name of The Linux Foundation nor the names of its 13 * contributors may be used to endorse or promote products derived 14 * from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 */ 29 30 // To remove 31 #include <utils/Log.h> 32 33 // System dependencies 34 #include <errno.h> 35 #include <fcntl.h> 36 #include <poll.h> 37 #include <pthread.h> 38 #include <sys/ioctl.h> 39 #include <sys/prctl.h> 40 #include <sys/stat.h> 41 #include <sys/types.h> 42 43 // Camera dependencies 44 #include "img_common.h" 45 #include "img_comp.h" 46 #include "img_comp_factory.h" 47 #include "img_buffer.h" 48 #include "lib2d.h" 49 #include "mm_lib2d.h" 50 51 /** lib2d_job_private_info 52 * @jobid: Job id of this process request 53 * @userdata: Client userdata that will be passed on callback 54 * @lib2d_client_cb: Application's callback function pointer 55 * which will be called upon completion of current job. 56 **/ 57 typedef struct lib2d_job_private_info_t { 58 int jobid; 59 void *userdata; 60 lib2d_error (*lib2d_client_cb) (void *userdata, int jobid); 61 } lib2d_job_private_info; 62 63 /** img_lib_t 64 * @ptr: handle to imglib library 65 * @img_core_get_comp: function pointer for img_core_get_comp 66 * @img_wait_for_completion: function pointer for img_wait_for_completion 67 **/ 68 typedef struct { 69 void *ptr; 70 int (*img_core_get_comp) (img_comp_role_t role, char *name, 71 img_core_ops_t *p_ops); 72 int (*img_wait_for_completion) (pthread_cond_t *p_cond, 73 pthread_mutex_t *p_mutex, int32_t ms); 74 } img_lib_t; 75 76 /** mm_lib2d_obj 77 * @core_ops: image core ops structure handle 78 * @comp: component structure handle 79 * @comp_mode: underlying component mode 80 * @lib2d_mode: lib2d mode requested by client 81 * @img_lib: imglib library, function ptrs handle 82 * @mutex: lib2d mutex used for synchronization 83 * @cond: librd cond used for synchronization 84 **/ 85 typedef struct mm_lib2d_obj_t { 86 img_core_ops_t core_ops; 87 img_component_ops_t comp; 88 img_comp_mode_t comp_mode; 89 lib2d_mode lib2d_mode; 90 img_lib_t img_lib; 91 pthread_mutex_t mutex; 92 pthread_cond_t cond; 93 } mm_lib2d_obj; 94 95 96 /** 97 * Function: lib2d_event_handler 98 * 99 * Description: Event handler. All the component events 100 * are received here. 101 * 102 * Input parameters: 103 * p_appdata - lib2d test object 104 * p_event - pointer to the event 105 * 106 * Return values: 107 * IMG_SUCCESS 108 * IMG_ERR_INVALID_INPUT 109 * 110 * Notes: none 111 **/ 112 int lib2d_event_handler(void* p_appdata, img_event_t *p_event) 113 { 114 mm_lib2d_obj *lib2d_obj = (mm_lib2d_obj *)p_appdata; 115 116 if ((NULL == p_event) || (NULL == p_appdata)) { 117 LOGE("invalid event"); 118 return IMG_ERR_INVALID_INPUT; 119 } 120 121 LOGD("type %d", p_event->type); 122 123 switch (p_event->type) { 124 case QIMG_EVT_DONE: 125 pthread_cond_signal(&lib2d_obj->cond); 126 break; 127 default:; 128 } 129 return IMG_SUCCESS; 130 } 131 132 /** 133 * Function: lib2d_callback_handler 134 * 135 * Description: Callback handler. Registered with Component 136 * on IMG_COMP_INIT. Will be called when processing 137 * of current request is completed. If component running in 138 * async mode, this is where client will know the execution 139 * is finished for in, out frames. 140 * 141 * Input parameters: 142 * p_appdata - lib2d test object 143 * p_in_frame - pointer to input frame 144 * p_out_frame - pointer to output frame 145 * 146 * Return values: 147 * IMG_SUCCESS 148 * IMG_ERR_GENERAL 149 * 150 * Notes: none 151 **/ 152 int lib2d_callback_handler(void *userdata, img_frame_t *p_in_frame, 153 img_frame_t *p_out_frame) 154 { 155 mm_lib2d_obj *lib2d_obj = (mm_lib2d_obj *)userdata; 156 lib2d_job_private_info *job_info = NULL; 157 158 if (NULL == userdata) { 159 LOGE("invalid event"); 160 return IMG_ERR_INVALID_INPUT; 161 } 162 163 // assert(p_in_frame->private_data == p_out_frame->private_data); 164 165 job_info = (lib2d_job_private_info *)p_in_frame->private_data; 166 if (job_info->lib2d_client_cb != NULL) { 167 job_info->lib2d_client_cb(job_info->userdata, job_info->jobid); 168 } 169 170 free(p_in_frame->private_data); 171 free(p_in_frame); 172 free(p_out_frame); 173 174 return IMG_SUCCESS; 175 } 176 177 /** 178 * Function: lib2d_fill_img_frame 179 * 180 * Description: Setup img_frame_t for given buffer 181 * 182 * Input parameters: 183 * p_frame - pointer to img_frame_t that needs to be setup 184 * lib2d_buffer - pointer to input buffer 185 * jobid - job id 186 * 187 * Return values: 188 * MM_LIB2D_SUCCESS 189 * MM_LIB2D_ERR_GENERAL 190 * 191 * Notes: none 192 **/ 193 lib2d_error lib2d_fill_img_frame(img_frame_t *p_frame, 194 mm_lib2d_buffer* lib2d_buffer, int jobid) 195 { 196 // use job id for now 197 p_frame->frame_cnt = jobid; 198 p_frame->idx = jobid; 199 p_frame->frame_id = jobid; 200 201 if (lib2d_buffer->buffer_type == MM_LIB2D_BUFFER_TYPE_RGB) { 202 mm_lib2d_rgb_buffer *rgb_buffer = &lib2d_buffer->rgb_buffer; 203 204 p_frame->info.num_planes = 1; 205 p_frame->info.width = rgb_buffer->width; 206 p_frame->info.height = rgb_buffer->height; 207 208 p_frame->frame[0].plane_cnt = 1; 209 p_frame->frame[0].plane[0].plane_type = PLANE_ARGB; 210 p_frame->frame[0].plane[0].addr = rgb_buffer->buffer; 211 p_frame->frame[0].plane[0].stride = rgb_buffer->stride; 212 p_frame->frame[0].plane[0].length = (rgb_buffer->stride * 213 rgb_buffer->height); 214 p_frame->frame[0].plane[0].fd = rgb_buffer->fd; 215 p_frame->frame[0].plane[0].height = rgb_buffer->height; 216 p_frame->frame[0].plane[0].width = rgb_buffer->width; 217 p_frame->frame[0].plane[0].offset = 0; 218 p_frame->frame[0].plane[0].scanline = rgb_buffer->height; 219 } else if (lib2d_buffer->buffer_type == MM_LIB2D_BUFFER_TYPE_YUV) { 220 mm_lib2d_yuv_buffer *yuv_buffer = &lib2d_buffer->yuv_buffer; 221 222 p_frame->info.num_planes = 2; 223 p_frame->info.width = yuv_buffer->width; 224 p_frame->info.height = yuv_buffer->height; 225 226 p_frame->frame[0].plane_cnt = 2; 227 p_frame->frame[0].plane[0].plane_type = PLANE_Y; 228 p_frame->frame[0].plane[0].addr = yuv_buffer->plane0; 229 p_frame->frame[0].plane[0].stride = yuv_buffer->stride0; 230 p_frame->frame[0].plane[0].length = (yuv_buffer->stride0 * 231 yuv_buffer->height); 232 p_frame->frame[0].plane[0].fd = yuv_buffer->fd; 233 p_frame->frame[0].plane[0].height = yuv_buffer->height; 234 p_frame->frame[0].plane[0].width = yuv_buffer->width; 235 p_frame->frame[0].plane[0].offset = 0; 236 p_frame->frame[0].plane[0].scanline = yuv_buffer->height; 237 238 if (yuv_buffer->format == CAM_FORMAT_YUV_420_NV12) { 239 p_frame->frame[0].plane[1].plane_type = PLANE_CB_CR; 240 } else if(yuv_buffer->format == CAM_FORMAT_YUV_420_NV21) { 241 p_frame->frame[0].plane[1].plane_type = PLANE_CR_CB; 242 } 243 p_frame->frame[0].plane[1].addr = yuv_buffer->plane1; 244 p_frame->frame[0].plane[1].stride = yuv_buffer->stride1; 245 p_frame->frame[0].plane[1].length = (yuv_buffer->stride1 * 246 yuv_buffer->height / 2); 247 p_frame->frame[0].plane[1].fd = yuv_buffer->fd; 248 p_frame->frame[0].plane[1].height = yuv_buffer->height; 249 p_frame->frame[0].plane[1].width = yuv_buffer->width; 250 p_frame->frame[0].plane[1].offset = 0; 251 p_frame->frame[0].plane[1].scanline = yuv_buffer->height; 252 } else { 253 return MM_LIB2D_ERR_GENERAL; 254 } 255 256 return MM_LIB2D_SUCCESS; 257 } 258 259 /** 260 * Function: mm_lib2d_init 261 * 262 * Description: Initialization function for Lib2D. src_format, dst_format 263 * are hints to the underlying component to initialize. 264 * 265 * Input parameters: 266 * mode - Mode (sync/async) in which App wants lib2d to run. 267 * src_format - source surface format 268 * dst_format - Destination surface format 269 * my_obj - handle that will be returned on succesful Init. App has to 270 * call other lib2d functions by passing this handle. 271 * 272 * Return values: 273 * MM_LIB2D_SUCCESS 274 * MM_LIB2D_ERR_MEMORY 275 * MM_LIB2D_ERR_BAD_PARAM 276 * MM_LIB2D_ERR_GENERAL 277 * 278 * Notes: none 279 **/ 280 lib2d_error mm_lib2d_init(lib2d_mode mode, cam_format_t src_format, 281 cam_format_t dst_format, void **my_obj) 282 { 283 int32_t rc = IMG_SUCCESS; 284 mm_lib2d_obj *lib2d_obj = NULL; 285 img_core_ops_t *p_core_ops = NULL; 286 img_component_ops_t *p_comp = NULL; 287 288 if (my_obj == NULL) { 289 return MM_LIB2D_ERR_BAD_PARAM; 290 } 291 292 // validate src_format, dst_format to check whether we support these. 293 // Currently support NV21 to ARGB conversions only. Others not tested. 294 if ((src_format != CAM_FORMAT_YUV_420_NV21) || 295 (dst_format != CAM_FORMAT_8888_ARGB)) { 296 LOGE("Formats conversion from %d to %d not supported", 297 src_format, dst_format); 298 } 299 300 lib2d_obj = malloc(sizeof(mm_lib2d_obj)); 301 if (lib2d_obj == NULL) { 302 return MM_LIB2D_ERR_MEMORY; 303 } 304 305 // Open libmmcamera_imglib 306 lib2d_obj->img_lib.ptr = dlopen("libmmcamera_imglib.so", RTLD_NOW); 307 if (!lib2d_obj->img_lib.ptr) { 308 LOGE("ERROR: couldn't dlopen libmmcamera_imglib.so: %s", 309 dlerror()); 310 goto FREE_LIB2D_OBJ; 311 } 312 313 /* Get function pointer for functions supported by C2D */ 314 *(void **)&lib2d_obj->img_lib.img_core_get_comp = 315 dlsym(lib2d_obj->img_lib.ptr, "img_core_get_comp"); 316 *(void **)&lib2d_obj->img_lib.img_wait_for_completion = 317 dlsym(lib2d_obj->img_lib.ptr, "img_wait_for_completion"); 318 319 /* Validate function pointers */ 320 if ((lib2d_obj->img_lib.img_core_get_comp == NULL) || 321 (lib2d_obj->img_lib.img_wait_for_completion == NULL)) { 322 LOGE(" ERROR mapping symbols from libc2d2.so"); 323 goto FREE_LIB2D_OBJ; 324 } 325 326 p_core_ops = &lib2d_obj->core_ops; 327 p_comp = &lib2d_obj->comp; 328 329 pthread_mutex_init(&lib2d_obj->mutex, NULL); 330 pthread_cond_init(&lib2d_obj->cond, NULL); 331 332 rc = lib2d_obj->img_lib.img_core_get_comp(IMG_COMP_LIB2D, 333 "qti.lib2d", p_core_ops); 334 if (rc != IMG_SUCCESS) { 335 LOGE("rc %d", rc); 336 goto FREE_LIB2D_OBJ; 337 } 338 339 rc = IMG_COMP_LOAD(p_core_ops, NULL); 340 if (rc != IMG_SUCCESS) { 341 LOGE("rc %d", rc); 342 goto FREE_LIB2D_OBJ; 343 } 344 345 rc = IMG_COMP_CREATE(p_core_ops, p_comp); 346 if (rc != IMG_SUCCESS) { 347 LOGE("rc %d", rc); 348 goto COMP_UNLOAD; 349 } 350 351 rc = IMG_COMP_INIT(p_comp, (void *)lib2d_obj, lib2d_callback_handler); 352 if (rc != IMG_SUCCESS) { 353 LOGE("rc %d", rc); 354 goto COMP_UNLOAD; 355 } 356 357 rc = IMG_COMP_SET_CB(p_comp, lib2d_event_handler); 358 if (rc != IMG_SUCCESS) { 359 LOGE("rc %d", rc); 360 goto COMP_DEINIT; 361 } 362 363 lib2d_obj->lib2d_mode = mode; 364 img_comp_mode_t comp_mode; 365 if (lib2d_obj->lib2d_mode == MM_LIB2D_SYNC_MODE) { 366 comp_mode = IMG_SYNC_MODE; 367 } else { 368 comp_mode = IMG_ASYNC_MODE; 369 } 370 371 // Set source format 372 rc = IMG_COMP_SET_PARAM(p_comp, QLIB2D_SOURCE_FORMAT, (void *)&src_format); 373 if (rc != IMG_SUCCESS) { 374 LOGE("rc %d", rc); 375 goto COMP_DEINIT; 376 } 377 378 // Set destination format 379 rc = IMG_COMP_SET_PARAM(p_comp, QLIB2D_DESTINATION_FORMAT, 380 (void *)&dst_format); 381 if (rc != IMG_SUCCESS) { 382 LOGE("rc %d", rc); 383 goto COMP_DEINIT; 384 } 385 386 // Try setting the required mode. 387 rc = IMG_COMP_SET_PARAM(p_comp, QIMG_PARAM_MODE, (void *)&comp_mode); 388 if (rc != IMG_SUCCESS) { 389 LOGE("rc %d", rc); 390 goto COMP_DEINIT; 391 } 392 393 // Get the mode to make sure whether the component is really running 394 // in the mode what we set. 395 rc = IMG_COMP_GET_PARAM(p_comp, QIMG_PARAM_MODE, 396 (void *)&lib2d_obj->comp_mode); 397 if (rc != IMG_SUCCESS) { 398 LOGE("rc %d", rc); 399 goto COMP_DEINIT; 400 } 401 402 if (comp_mode != lib2d_obj->comp_mode) { 403 LOGD("Component is running in %d mode", 404 lib2d_obj->comp_mode); 405 } 406 407 *my_obj = (void *)lib2d_obj; 408 409 return MM_LIB2D_SUCCESS; 410 411 COMP_DEINIT : 412 rc = IMG_COMP_DEINIT(p_comp); 413 if (rc != IMG_SUCCESS) { 414 LOGE("rc %d", rc); 415 return MM_LIB2D_ERR_GENERAL; 416 } 417 418 COMP_UNLOAD : 419 rc = IMG_COMP_UNLOAD(p_core_ops); 420 if (rc != IMG_SUCCESS) { 421 LOGE("rc %d", rc); 422 return MM_LIB2D_ERR_GENERAL; 423 } 424 425 FREE_LIB2D_OBJ : 426 free(lib2d_obj); 427 return MM_LIB2D_ERR_GENERAL; 428 } 429 430 /** 431 * Function: mm_lib2d_deinit 432 * 433 * Description: De-Initialization function for Lib2D 434 * 435 * Input parameters: 436 * lib2d_obj_handle - handle tto the lib2d object 437 * 438 * Return values: 439 * MM_LIB2D_SUCCESS 440 * MM_LIB2D_ERR_GENERAL 441 * 442 * Notes: none 443 **/ 444 lib2d_error mm_lib2d_deinit(void *lib2d_obj_handle) 445 { 446 mm_lib2d_obj *lib2d_obj = (mm_lib2d_obj *)lib2d_obj_handle; 447 int rc = IMG_SUCCESS; 448 img_core_ops_t *p_core_ops = &lib2d_obj->core_ops; 449 img_component_ops_t *p_comp = &lib2d_obj->comp; 450 451 rc = IMG_COMP_DEINIT(p_comp); 452 if (rc != IMG_SUCCESS) { 453 LOGE("rc %d", rc); 454 return MM_LIB2D_ERR_GENERAL; 455 } 456 457 rc = IMG_COMP_UNLOAD(p_core_ops); 458 if (rc != IMG_SUCCESS) { 459 LOGE("rc %d", rc); 460 return MM_LIB2D_ERR_GENERAL; 461 } 462 463 dlclose(lib2d_obj->img_lib.ptr); 464 free(lib2d_obj); 465 466 return MM_LIB2D_SUCCESS; 467 } 468 469 /** 470 * Function: mm_lib2d_start_job 471 * 472 * Description: Start executing the job 473 * 474 * Input parameters: 475 * lib2d_obj_handle - handle tto the lib2d object 476 * src_buffer - pointer to the source buffer 477 * dst_buffer - pointer to the destination buffer 478 * jobid - job id of this request 479 * userdata - userdata that will be pass through callback function 480 * cb - callback function that will be called on completion of this job 481 * 482 * Return values: 483 * MM_LIB2D_SUCCESS 484 * MM_LIB2D_ERR_MEMORY 485 * MM_LIB2D_ERR_GENERAL 486 * 487 * Notes: none 488 **/ 489 lib2d_error mm_lib2d_start_job(void *lib2d_obj_handle, 490 mm_lib2d_buffer* src_buffer, mm_lib2d_buffer* dst_buffer, 491 int jobid, void *userdata, lib2d_client_cb cb) 492 { 493 mm_lib2d_obj *lib2d_obj = (mm_lib2d_obj *)lib2d_obj_handle; 494 int rc = IMG_SUCCESS; 495 img_core_ops_t *p_core_ops = &lib2d_obj->core_ops; 496 img_component_ops_t *p_comp = &lib2d_obj->comp; 497 498 img_frame_t *p_in_frame = malloc(sizeof(img_frame_t)); 499 if (p_in_frame == NULL) { 500 return MM_LIB2D_ERR_MEMORY; 501 } 502 503 img_frame_t *p_out_frame = malloc(sizeof(img_frame_t)); 504 if (p_out_frame == NULL) { 505 free(p_in_frame); 506 return MM_LIB2D_ERR_MEMORY; 507 } 508 509 lib2d_job_private_info *p_job_info = malloc(sizeof(lib2d_job_private_info)); 510 if (p_out_frame == NULL) { 511 free(p_in_frame); 512 free(p_out_frame); 513 return MM_LIB2D_ERR_MEMORY; 514 } 515 516 memset(p_in_frame, 0x0, sizeof(img_frame_t)); 517 memset(p_out_frame, 0x0, sizeof(img_frame_t)); 518 memset(p_job_info, 0x0, sizeof(lib2d_job_private_info)); 519 520 // Fill up job info private data structure that can be used in callback to 521 // inform back to the client. 522 p_job_info->jobid = jobid; 523 p_job_info->userdata = userdata; 524 p_job_info->lib2d_client_cb = cb; 525 526 p_in_frame->private_data = (void *)p_job_info; 527 p_out_frame->private_data = (void *)p_job_info; 528 529 // convert the input info into component understandble data structures 530 531 // Prepare Input, output frames 532 lib2d_fill_img_frame(p_in_frame, src_buffer, jobid); 533 lib2d_fill_img_frame(p_out_frame, dst_buffer, jobid); 534 535 // call set_param to set the source, destination formats 536 537 rc = IMG_COMP_Q_BUF(p_comp, p_in_frame, IMG_IN); 538 if (rc != IMG_SUCCESS) { 539 LOGE("rc %d", rc); 540 goto ERROR; 541 } 542 543 rc = IMG_COMP_Q_BUF(p_comp, p_out_frame, IMG_OUT); 544 if (rc != IMG_SUCCESS) { 545 LOGE("rc %d", rc); 546 goto ERROR; 547 } 548 549 rc = IMG_COMP_START(p_comp, NULL); 550 if (rc != IMG_SUCCESS) { 551 LOGE("rc %d", rc); 552 goto ERROR; 553 } 554 555 if (lib2d_obj->lib2d_mode == MM_LIB2D_SYNC_MODE) { 556 if (lib2d_obj->comp_mode == IMG_ASYNC_MODE) { 557 LOGD("before wait rc %d", rc); 558 rc = lib2d_obj->img_lib.img_wait_for_completion(&lib2d_obj->cond, 559 &lib2d_obj->mutex, 10000); 560 if (rc != IMG_SUCCESS) { 561 LOGE("rc %d", rc); 562 goto ERROR; 563 } 564 } 565 } 566 567 rc = IMG_COMP_ABORT(p_comp, NULL); 568 if (IMG_ERROR(rc)) { 569 LOGE("comp abort failed %d", rc); 570 return rc; 571 } 572 573 return MM_LIB2D_SUCCESS; 574 ERROR: 575 free(p_in_frame); 576 free(p_out_frame); 577 free(p_job_info); 578 579 return MM_LIB2D_ERR_GENERAL; 580 } 581 582