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 #include "img_meta.h" 51 52 /** lib2d_job_private_info 53 * @jobid: Job id of this process request 54 * @userdata: Client userdata that will be passed on callback 55 * @lib2d_client_cb: Application's callback function pointer 56 * which will be called upon completion of current job. 57 **/ 58 typedef struct lib2d_job_private_info_t { 59 int jobid; 60 void *userdata; 61 lib2d_error (*lib2d_client_cb) (void *userdata, int jobid); 62 } lib2d_job_private_info; 63 64 /** img_lib_t 65 * @ptr: handle to imglib library 66 * @img_core_get_comp: function pointer for img_core_get_comp 67 * @img_wait_for_completion: function pointer for img_wait_for_completion 68 **/ 69 typedef struct { 70 void *ptr; 71 int (*img_core_get_comp) (img_comp_role_t role, char *name, 72 img_core_ops_t *p_ops); 73 int (*img_wait_for_completion) (pthread_cond_t *p_cond, 74 pthread_mutex_t *p_mutex, int32_t ms); 75 } img_lib_t; 76 77 /** mm_lib2d_obj 78 * @core_ops: image core ops structure handle 79 * @comp: component structure handle 80 * @comp_mode: underlying component mode 81 * @lib2d_mode: lib2d mode requested by client 82 * @img_lib: imglib library, function ptrs handle 83 * @mutex: lib2d mutex used for synchronization 84 * @cond: librd cond used for synchronization 85 **/ 86 typedef struct mm_lib2d_obj_t { 87 img_core_ops_t core_ops; 88 img_component_ops_t comp; 89 img_comp_mode_t comp_mode; 90 lib2d_mode lib2d_mode; 91 img_lib_t img_lib; 92 pthread_mutex_t mutex; 93 pthread_cond_t cond; 94 } mm_lib2d_obj; 95 96 97 /** 98 * Function: lib2d_event_handler 99 * 100 * Description: Event handler. All the component events 101 * are received here. 102 * 103 * Input parameters: 104 * p_appdata - lib2d test object 105 * p_event - pointer to the event 106 * 107 * Return values: 108 * IMG_SUCCESS 109 * IMG_ERR_INVALID_INPUT 110 * 111 * Notes: none 112 **/ 113 int lib2d_event_handler(void* p_appdata, img_event_t *p_event) 114 { 115 mm_lib2d_obj *lib2d_obj = (mm_lib2d_obj *)p_appdata; 116 117 if ((NULL == p_event) || (NULL == p_appdata)) { 118 LOGE("invalid event"); 119 return IMG_ERR_INVALID_INPUT; 120 } 121 122 LOGD("type %d", p_event->type); 123 124 switch (p_event->type) { 125 case QIMG_EVT_DONE: 126 pthread_cond_signal(&lib2d_obj->cond); 127 break; 128 default:; 129 } 130 return IMG_SUCCESS; 131 } 132 133 /** 134 * Function: lib2d_callback_handler 135 * 136 * Description: Callback handler. Registered with Component 137 * on IMG_COMP_INIT. Will be called when processing 138 * of current request is completed. If component running in 139 * async mode, this is where client will know the execution 140 * is finished for in, out frames. 141 * 142 * Input parameters: 143 * p_appdata - lib2d test object 144 * p_in_frame - pointer to input frame 145 * p_out_frame - pointer to output frame 146 * p_meta - pointer to meta data 147 * 148 * Return values: 149 * IMG_SUCCESS 150 * IMG_ERR_GENERAL 151 * 152 * Notes: none 153 **/ 154 int lib2d_callback_handler(void *userdata, img_frame_t *p_in_frame, 155 img_frame_t *p_out_frame, img_meta_t *p_meta) 156 { 157 lib2d_job_private_info *job_info = NULL; 158 159 if (NULL == userdata) { 160 LOGE("invalid event"); 161 return IMG_ERR_INVALID_INPUT; 162 } 163 164 // assert(p_in_frame->private_data == p_out_frame->private_data); 165 166 job_info = (lib2d_job_private_info *)p_in_frame->private_data; 167 if (job_info->lib2d_client_cb != NULL) { 168 job_info->lib2d_client_cb(job_info->userdata, job_info->jobid); 169 } 170 171 free(p_in_frame->private_data); 172 free(p_in_frame); 173 free(p_out_frame); 174 free(p_meta); 175 176 return IMG_SUCCESS; 177 } 178 179 /** 180 * Function: lib2d_fill_img_frame 181 * 182 * Description: Setup img_frame_t for given buffer 183 * 184 * Input parameters: 185 * p_frame - pointer to img_frame_t that needs to be setup 186 * lib2d_buffer - pointer to input buffer 187 * jobid - job id 188 * 189 * Return values: 190 * MM_LIB2D_SUCCESS 191 * MM_LIB2D_ERR_GENERAL 192 * 193 * Notes: none 194 **/ 195 lib2d_error lib2d_fill_img_frame(img_frame_t *p_frame, 196 mm_lib2d_buffer* lib2d_buffer, int jobid) 197 { 198 // use job id for now 199 p_frame->frame_cnt = jobid; 200 p_frame->idx = jobid; 201 p_frame->frame_id = jobid; 202 203 if (lib2d_buffer->buffer_type == MM_LIB2D_BUFFER_TYPE_RGB) { 204 mm_lib2d_rgb_buffer *rgb_buffer = &lib2d_buffer->rgb_buffer; 205 206 p_frame->info.num_planes = 1; 207 p_frame->info.width = rgb_buffer->width; 208 p_frame->info.height = rgb_buffer->height; 209 210 p_frame->frame[0].plane_cnt = 1; 211 p_frame->frame[0].plane[0].plane_type = PLANE_ARGB; 212 p_frame->frame[0].plane[0].addr = rgb_buffer->buffer; 213 p_frame->frame[0].plane[0].stride = rgb_buffer->stride; 214 p_frame->frame[0].plane[0].length = (rgb_buffer->stride * 215 rgb_buffer->height); 216 p_frame->frame[0].plane[0].fd = rgb_buffer->fd; 217 p_frame->frame[0].plane[0].height = rgb_buffer->height; 218 p_frame->frame[0].plane[0].width = rgb_buffer->width; 219 p_frame->frame[0].plane[0].offset = 0; 220 p_frame->frame[0].plane[0].scanline = rgb_buffer->height; 221 } else if (lib2d_buffer->buffer_type == MM_LIB2D_BUFFER_TYPE_YUV) { 222 mm_lib2d_yuv_buffer *yuv_buffer = &lib2d_buffer->yuv_buffer; 223 224 p_frame->info.num_planes = 2; 225 p_frame->info.width = yuv_buffer->width; 226 p_frame->info.height = yuv_buffer->height; 227 228 p_frame->frame[0].plane_cnt = 2; 229 p_frame->frame[0].plane[0].plane_type = PLANE_Y; 230 p_frame->frame[0].plane[0].addr = yuv_buffer->plane0; 231 p_frame->frame[0].plane[0].stride = yuv_buffer->stride0; 232 p_frame->frame[0].plane[0].length = (yuv_buffer->stride0 * 233 yuv_buffer->height); 234 p_frame->frame[0].plane[0].fd = yuv_buffer->fd; 235 p_frame->frame[0].plane[0].height = yuv_buffer->height; 236 p_frame->frame[0].plane[0].width = yuv_buffer->width; 237 p_frame->frame[0].plane[0].offset = 0; 238 p_frame->frame[0].plane[0].scanline = yuv_buffer->height; 239 240 if (yuv_buffer->format == CAM_FORMAT_YUV_420_NV12) { 241 p_frame->frame[0].plane[1].plane_type = PLANE_CB_CR; 242 } else if(yuv_buffer->format == CAM_FORMAT_YUV_420_NV21) { 243 p_frame->frame[0].plane[1].plane_type = PLANE_CR_CB; 244 } 245 p_frame->frame[0].plane[1].addr = yuv_buffer->plane1; 246 p_frame->frame[0].plane[1].stride = yuv_buffer->stride1; 247 p_frame->frame[0].plane[1].length = (yuv_buffer->stride1 * 248 yuv_buffer->height / 2); 249 p_frame->frame[0].plane[1].fd = yuv_buffer->fd; 250 p_frame->frame[0].plane[1].height = yuv_buffer->height; 251 p_frame->frame[0].plane[1].width = yuv_buffer->width; 252 p_frame->frame[0].plane[1].offset = 0; 253 p_frame->frame[0].plane[1].scanline = yuv_buffer->height; 254 } else { 255 return MM_LIB2D_ERR_GENERAL; 256 } 257 258 return MM_LIB2D_SUCCESS; 259 } 260 261 /** 262 * Function: mm_lib2d_init 263 * 264 * Description: Initialization function for Lib2D. src_format, dst_format 265 * are hints to the underlying component to initialize. 266 * 267 * Input parameters: 268 * mode - Mode (sync/async) in which App wants lib2d to run. 269 * src_format - source surface format 270 * dst_format - Destination surface format 271 * my_obj - handle that will be returned on succesful Init. App has to 272 * call other lib2d functions by passing this handle. 273 * 274 * Return values: 275 * MM_LIB2D_SUCCESS 276 * MM_LIB2D_ERR_MEMORY 277 * MM_LIB2D_ERR_BAD_PARAM 278 * MM_LIB2D_ERR_GENERAL 279 * 280 * Notes: none 281 **/ 282 283 lib2d_error mm_lib2d_init(lib2d_mode mode, cam_format_t src_format, 284 cam_format_t dst_format, void **my_obj) 285 { 286 int32_t rc = IMG_SUCCESS; 287 mm_lib2d_obj *lib2d_obj = NULL; 288 img_core_ops_t *p_core_ops = NULL; 289 img_component_ops_t *p_comp = NULL; 290 291 if (my_obj == NULL) { 292 return MM_LIB2D_ERR_BAD_PARAM; 293 } 294 295 // validate src_format, dst_format to check whether we support these. 296 // Currently support NV21 to ARGB conversions only. Others not tested. 297 if ((src_format != CAM_FORMAT_YUV_420_NV21) || 298 (dst_format != CAM_FORMAT_8888_ARGB)) { 299 LOGE("Formats conversion from %d to %d not supported", 300 src_format, dst_format); 301 } 302 303 lib2d_obj = malloc(sizeof(mm_lib2d_obj)); 304 if (lib2d_obj == NULL) { 305 return MM_LIB2D_ERR_MEMORY; 306 } 307 308 // Open libmmcamera_imglib 309 lib2d_obj->img_lib.ptr = dlopen("libmmcamera_imglib.so", RTLD_NOW); 310 if (!lib2d_obj->img_lib.ptr) { 311 LOGE("ERROR: couldn't dlopen libmmcamera_imglib.so: %s", 312 dlerror()); 313 goto FREE_LIB2D_OBJ; 314 } 315 316 /* Get function pointer for functions supported by C2D */ 317 *(void **)&lib2d_obj->img_lib.img_core_get_comp = 318 dlsym(lib2d_obj->img_lib.ptr, "img_core_get_comp"); 319 *(void **)&lib2d_obj->img_lib.img_wait_for_completion = 320 dlsym(lib2d_obj->img_lib.ptr, "img_wait_for_completion"); 321 322 /* Validate function pointers */ 323 if ((lib2d_obj->img_lib.img_core_get_comp == NULL) || 324 (lib2d_obj->img_lib.img_wait_for_completion == NULL)) { 325 LOGE(" ERROR mapping symbols from libc2d2.so"); 326 goto FREE_LIB2D_OBJ; 327 } 328 329 p_core_ops = &lib2d_obj->core_ops; 330 p_comp = &lib2d_obj->comp; 331 332 pthread_mutex_init(&lib2d_obj->mutex, NULL); 333 pthread_cond_init(&lib2d_obj->cond, NULL); 334 335 rc = lib2d_obj->img_lib.img_core_get_comp(IMG_COMP_LIB2D, 336 "qti.lib2d", p_core_ops); 337 if (rc != IMG_SUCCESS) { 338 LOGE("rc %d", rc); 339 goto FREE_LIB2D_OBJ; 340 } 341 342 rc = IMG_COMP_LOAD(p_core_ops, NULL); 343 if (rc != IMG_SUCCESS) { 344 LOGE("rc %d", rc); 345 goto FREE_LIB2D_OBJ; 346 } 347 348 rc = IMG_COMP_CREATE(p_core_ops, p_comp); 349 if (rc != IMG_SUCCESS) { 350 LOGE("rc %d", rc); 351 goto COMP_UNLOAD; 352 } 353 354 rc = IMG_COMP_INIT(p_comp, (void *)lib2d_obj, lib2d_callback_handler); 355 if (rc != IMG_SUCCESS) { 356 LOGE("rc %d", rc); 357 goto COMP_UNLOAD; 358 } 359 360 rc = IMG_COMP_SET_CB(p_comp, lib2d_event_handler); 361 if (rc != IMG_SUCCESS) { 362 LOGE("rc %d", rc); 363 goto COMP_DEINIT; 364 } 365 366 lib2d_obj->lib2d_mode = mode; 367 img_comp_mode_t comp_mode; 368 if (lib2d_obj->lib2d_mode == MM_LIB2D_SYNC_MODE) { 369 comp_mode = IMG_SYNC_MODE; 370 } else { 371 comp_mode = IMG_ASYNC_MODE; 372 } 373 374 // Set source format 375 rc = IMG_COMP_SET_PARAM(p_comp, QLIB2D_SOURCE_FORMAT, (void *)&src_format); 376 if (rc != IMG_SUCCESS) { 377 LOGE("rc %d", rc); 378 goto COMP_DEINIT; 379 } 380 381 // Set destination format 382 rc = IMG_COMP_SET_PARAM(p_comp, QLIB2D_DESTINATION_FORMAT, 383 (void *)&dst_format); 384 if (rc != IMG_SUCCESS) { 385 LOGE("rc %d", rc); 386 goto COMP_DEINIT; 387 } 388 389 // Try setting the required mode. 390 rc = IMG_COMP_SET_PARAM(p_comp, QIMG_PARAM_MODE, (void *)&comp_mode); 391 if (rc != IMG_SUCCESS) { 392 LOGE("rc %d", rc); 393 goto COMP_DEINIT; 394 } 395 396 // Get the mode to make sure whether the component is really running 397 // in the mode what we set. 398 rc = IMG_COMP_GET_PARAM(p_comp, QIMG_PARAM_MODE, 399 (void *)&lib2d_obj->comp_mode); 400 if (rc != IMG_SUCCESS) { 401 LOGE("rc %d", rc); 402 goto COMP_DEINIT; 403 } 404 405 if (comp_mode != lib2d_obj->comp_mode) { 406 LOGD("Component is running in %d mode", 407 lib2d_obj->comp_mode); 408 } 409 410 *my_obj = (void *)lib2d_obj; 411 412 return MM_LIB2D_SUCCESS; 413 414 COMP_DEINIT : 415 rc = IMG_COMP_DEINIT(p_comp); 416 if (rc != IMG_SUCCESS) { 417 LOGE("rc %d", rc); 418 return MM_LIB2D_ERR_GENERAL; 419 } 420 421 COMP_UNLOAD : 422 rc = IMG_COMP_UNLOAD(p_core_ops); 423 if (rc != IMG_SUCCESS) { 424 LOGE("rc %d", rc); 425 return MM_LIB2D_ERR_GENERAL; 426 } 427 428 FREE_LIB2D_OBJ : 429 free(lib2d_obj); 430 return MM_LIB2D_ERR_GENERAL; 431 } 432 433 /** 434 * Function: mm_lib2d_deinit 435 * 436 * Description: De-Initialization function for Lib2D 437 * 438 * Input parameters: 439 * lib2d_obj_handle - handle tto the lib2d object 440 * 441 * Return values: 442 * MM_LIB2D_SUCCESS 443 * MM_LIB2D_ERR_GENERAL 444 * 445 * Notes: none 446 **/ 447 lib2d_error mm_lib2d_deinit(void *lib2d_obj_handle) 448 { 449 mm_lib2d_obj *lib2d_obj = (mm_lib2d_obj *)lib2d_obj_handle; 450 int rc = IMG_SUCCESS; 451 img_core_ops_t *p_core_ops = &lib2d_obj->core_ops; 452 img_component_ops_t *p_comp = &lib2d_obj->comp; 453 454 rc = IMG_COMP_DEINIT(p_comp); 455 if (rc != IMG_SUCCESS) { 456 LOGE("rc %d", rc); 457 return MM_LIB2D_ERR_GENERAL; 458 } 459 460 rc = IMG_COMP_UNLOAD(p_core_ops); 461 if (rc != IMG_SUCCESS) { 462 LOGE("rc %d", rc); 463 return MM_LIB2D_ERR_GENERAL; 464 } 465 466 dlclose(lib2d_obj->img_lib.ptr); 467 free(lib2d_obj); 468 469 return MM_LIB2D_SUCCESS; 470 } 471 472 /** 473 * Function: mm_lib2d_start_job 474 * 475 * Description: Start executing the job 476 * 477 * Input parameters: 478 * lib2d_obj_handle - handle tto the lib2d object 479 * src_buffer - pointer to the source buffer 480 * dst_buffer - pointer to the destination buffer 481 * jobid - job id of this request 482 * userdata - userdata that will be pass through callback function 483 * cb - callback function that will be called on completion of this job 484 * rotation - rotation to be applied 485 * 486 * Return values: 487 * MM_LIB2D_SUCCESS 488 * MM_LIB2D_ERR_MEMORY 489 * MM_LIB2D_ERR_GENERAL 490 * 491 * Notes: none 492 **/ 493 lib2d_error mm_lib2d_start_job(void *lib2d_obj_handle, 494 mm_lib2d_buffer* src_buffer, mm_lib2d_buffer* dst_buffer, 495 int jobid, void *userdata, lib2d_client_cb cb, uint32_t rotation) 496 { 497 mm_lib2d_obj *lib2d_obj = (mm_lib2d_obj *)lib2d_obj_handle; 498 int rc = IMG_SUCCESS; 499 img_component_ops_t *p_comp = &lib2d_obj->comp; 500 501 img_frame_t *p_in_frame = malloc(sizeof(img_frame_t)); 502 if (p_in_frame == NULL) { 503 return MM_LIB2D_ERR_MEMORY; 504 } 505 506 img_frame_t *p_out_frame = malloc(sizeof(img_frame_t)); 507 if (p_out_frame == NULL) { 508 free(p_in_frame); 509 return MM_LIB2D_ERR_MEMORY; 510 } 511 512 img_meta_t *p_meta = malloc(sizeof(img_meta_t)); 513 if (p_meta == NULL) { 514 free(p_in_frame); 515 free(p_out_frame); 516 return MM_LIB2D_ERR_MEMORY; 517 } 518 519 lib2d_job_private_info *p_job_info = malloc(sizeof(lib2d_job_private_info)); 520 if (p_out_frame == NULL) { 521 free(p_in_frame); 522 free(p_out_frame); 523 free(p_meta); 524 return MM_LIB2D_ERR_MEMORY; 525 } 526 527 memset(p_in_frame, 0x0, sizeof(img_frame_t)); 528 memset(p_out_frame, 0x0, sizeof(img_frame_t)); 529 memset(p_meta, 0x0, sizeof(img_meta_t)); 530 memset(p_job_info, 0x0, sizeof(lib2d_job_private_info)); 531 532 // Fill up job info private data structure that can be used in callback to 533 // inform back to the client. 534 p_job_info->jobid = jobid; 535 p_job_info->userdata = userdata; 536 p_job_info->lib2d_client_cb = cb; 537 538 p_in_frame->private_data = (void *)p_job_info; 539 p_out_frame->private_data = (void *)p_job_info; 540 541 // convert the input info into component understandble data structures 542 543 // Prepare Input, output frames 544 lib2d_fill_img_frame(p_in_frame, src_buffer, jobid); 545 lib2d_fill_img_frame(p_out_frame, dst_buffer, jobid); 546 547 p_meta->frame_id = jobid; 548 p_meta->rotation.device_rotation = (int32_t)rotation; 549 p_meta->rotation.frame_rotation = (int32_t)rotation; 550 551 // call set_param to set the source, destination formats 552 553 rc = IMG_COMP_Q_BUF(p_comp, p_in_frame, IMG_IN); 554 if (rc != IMG_SUCCESS) { 555 LOGE("rc %d", rc); 556 goto ERROR; 557 } 558 559 rc = IMG_COMP_Q_BUF(p_comp, p_out_frame, IMG_OUT); 560 if (rc != IMG_SUCCESS) { 561 LOGE("rc %d", rc); 562 goto ERROR; 563 } 564 565 rc = IMG_COMP_Q_META_BUF(p_comp, p_meta); 566 if (rc != IMG_SUCCESS) { 567 LOGE("rc %d", rc); 568 goto ERROR; 569 } 570 571 rc = IMG_COMP_START(p_comp, NULL); 572 if (rc != IMG_SUCCESS) { 573 LOGE("rc %d", rc); 574 goto ERROR; 575 } 576 577 if (lib2d_obj->lib2d_mode == MM_LIB2D_SYNC_MODE) { 578 if (lib2d_obj->comp_mode == IMG_ASYNC_MODE) { 579 LOGD("before wait rc %d", rc); 580 rc = lib2d_obj->img_lib.img_wait_for_completion(&lib2d_obj->cond, 581 &lib2d_obj->mutex, 10000); 582 if (rc != IMG_SUCCESS) { 583 LOGE("rc %d", rc); 584 goto ERROR; 585 } 586 } 587 } 588 589 rc = IMG_COMP_ABORT(p_comp, NULL); 590 if (IMG_ERROR(rc)) { 591 LOGE("comp abort failed %d", rc); 592 return rc; 593 } 594 595 return MM_LIB2D_SUCCESS; 596 ERROR: 597 free(p_in_frame); 598 free(p_out_frame); 599 free(p_meta); 600 free(p_job_info); 601 602 return MM_LIB2D_ERR_GENERAL; 603 } 604 605