1 /* 2 Copyright (c) 2012, The Linux Foundation. All rights reserved. 3 4 Redistribution and use in source and binary forms, with or without 5 modification, are permitted provided that the following conditions are 6 met: 7 * Redistributions of source code must retain the above copyright 8 notice, this list of conditions and the following disclaimer. 9 * Redistributions in binary form must reproduce the above 10 copyright notice, this list of conditions and the following 11 disclaimer in the documentation and/or other materials provided 12 with the distribution. 13 * Neither the name of The Linux Foundation nor the names of its 14 contributors may be used to endorse or promote products derived 15 from this software without specific prior written permission. 16 17 THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 18 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 21 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 24 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <pthread.h> 31 #include <errno.h> 32 #include <sys/ioctl.h> 33 #include <sys/types.h> 34 #include <sys/stat.h> 35 #include <fcntl.h> 36 #include <poll.h> 37 #include <semaphore.h> 38 39 #include "mm_jpeg_dbg.h" 40 #include "mm_jpeg_interface.h" 41 #include "mm_jpeg.h" 42 43 /* define max num of supported concurrent jpeg jobs by OMX engine. 44 * Current, only one per time */ 45 #define NUM_MAX_JPEG_CNCURRENT_JOBS 1 46 47 #define INPUT_PORT_MAIN 0 48 #define INPUT_PORT_THUMBNAIL 2 49 #define OUTPUT_PORT 1 50 51 void mm_jpeg_job_wait_for_event(mm_jpeg_obj *my_obj, uint32_t evt_mask); 52 void mm_jpeg_job_wait_for_cmd_complete(mm_jpeg_obj *my_obj, 53 int cmd, 54 int status); 55 OMX_ERRORTYPE mm_jpeg_etbdone(OMX_HANDLETYPE hComponent, 56 OMX_PTR pAppData, 57 OMX_BUFFERHEADERTYPE* pBuffer); 58 OMX_ERRORTYPE mm_jpeg_ftbdone(OMX_HANDLETYPE hComponent, 59 OMX_PTR pAppData, 60 OMX_BUFFERHEADERTYPE* pBuffer); 61 OMX_ERRORTYPE mm_jpeg_handle_omx_event(OMX_HANDLETYPE hComponent, 62 OMX_PTR pAppData, 63 OMX_EVENTTYPE eEvent, 64 OMX_U32 nData1, 65 OMX_U32 nData2, 66 OMX_PTR pEventData); 67 /* special queue functions for job queue */ 68 int32_t mm_jpeg_queue_update_flag(mm_jpeg_queue_t* queue, uint32_t job_id, uint8_t flag); 69 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_client_id(mm_jpeg_queue_t* queue, uint32_t client_hdl); 70 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_job_id(mm_jpeg_queue_t* queue, uint32_t job_id); 71 72 int32_t mm_jpeg_omx_load(mm_jpeg_obj* my_obj) 73 { 74 int32_t rc = 0; 75 OMX_CALLBACKTYPE callbacks; 76 77 callbacks.EmptyBufferDone = mm_jpeg_etbdone; 78 callbacks.FillBufferDone = mm_jpeg_ftbdone; 79 callbacks.EventHandler = mm_jpeg_handle_omx_event; 80 rc = OMX_GetHandle(&my_obj->omx_handle, 81 "OMX.qcom.image.jpeg.encoder", 82 (void*)my_obj, 83 &callbacks); 84 85 if (0 != rc) { 86 CDBG_ERROR("%s : OMX_GetHandle failed (%d)",__func__, rc); 87 return rc; 88 } 89 90 rc = OMX_Init(); 91 if (0 != rc) { 92 CDBG_ERROR("%s : OMX_Init failed (%d)",__func__, rc); 93 OMX_FreeHandle(my_obj->omx_handle); 94 } 95 96 return rc; 97 } 98 99 int32_t mm_jpeg_omx_unload(mm_jpeg_obj *my_obj) 100 { 101 int32_t rc = 0; 102 rc = OMX_Deinit(); 103 OMX_FreeHandle(my_obj->omx_handle); 104 105 return rc; 106 } 107 108 int32_t mm_jpeg_omx_abort_job(mm_jpeg_obj *my_obj, mm_jpeg_job_entry* job_entry) 109 { 110 int32_t rc = 0; 111 uint8_t i, j; 112 113 OMX_SendCommand(my_obj->omx_handle, OMX_CommandFlush, 0, NULL); 114 mm_jpeg_job_wait_for_event(my_obj, 115 MM_JPEG_EVENT_MASK_JPEG_DONE|MM_JPEG_EVENT_MASK_JPEG_ABORT|MM_JPEG_EVENT_MASK_JPEG_ERROR); 116 CDBG("%s:waitForEvent: OMX_CommandFlush: DONE", __func__); 117 118 OMX_SendCommand(my_obj->omx_handle, OMX_CommandStateSet, OMX_StateIdle, NULL); 119 OMX_SendCommand(my_obj->omx_handle, OMX_CommandStateSet, OMX_StateLoaded, NULL); 120 121 /* free buffers used in OMX processing */ 122 for (i = 0; i < JPEG_SRC_IMAGE_TYPE_MAX; i++) { 123 for (j = 0; j < job_entry->src_bufs[i].num_bufs; j++) { 124 if (NULL != job_entry->src_bufs[i].bufs[j].buf_header) { 125 OMX_FreeBuffer(my_obj->omx_handle, 126 job_entry->src_bufs[i].bufs[j].portIdx, 127 job_entry->src_bufs[i].bufs[j].buf_header); 128 } 129 } 130 } 131 OMX_FreeBuffer(my_obj->omx_handle, 132 job_entry->sink_buf.portIdx, 133 job_entry->sink_buf.buf_header); 134 135 return rc; 136 } 137 138 /* TODO: needs revisit after omx lib supports multi src buffers */ 139 int32_t mm_jpeg_omx_config_main_buffer_offset(mm_jpeg_obj* my_obj, src_image_buffer_info *src_buf) 140 { 141 int32_t rc = 0; 142 uint8_t i; 143 OMX_INDEXTYPE buf_offset_idx; 144 omx_jpeg_buffer_offset buffer_offset; 145 146 for (i = 0; i < src_buf->num_bufs; i++) { 147 OMX_GetExtensionIndex(my_obj->omx_handle, 148 "omx.qcom.jpeg.exttype.buffer_offset", 149 &buf_offset_idx); 150 memset(&buffer_offset, 0, sizeof(buffer_offset)); 151 152 switch (src_buf->img_fmt) { 153 case JPEG_SRC_IMAGE_FMT_YUV: 154 if (1 == src_buf->src_image[i].offset.num_planes) { 155 buffer_offset.yOffset = 156 src_buf->src_image[i].offset.sp.y_offset; 157 buffer_offset.cbcrOffset = 158 src_buf->src_image[i].offset.sp.cbcr_offset; 159 buffer_offset.totalSize = 160 src_buf->src_image[i].offset.sp.len; 161 } else { 162 buffer_offset.yOffset = 163 src_buf->src_image[i].offset.mp[0].offset; 164 buffer_offset.cbcrOffset = 165 src_buf->src_image[i].offset.mp[1].offset; 166 buffer_offset.totalSize = 167 src_buf->src_image[i].offset.frame_len; 168 } 169 CDBG("%s: idx=%d, yOffset =%d, cbcrOffset =%d, totalSize = %d\n", 170 __func__, i, buffer_offset.yOffset, buffer_offset.cbcrOffset, buffer_offset.totalSize); 171 OMX_SetParameter(my_obj->omx_handle, buf_offset_idx, &buffer_offset); 172 break; 173 case JPEG_SRC_IMAGE_FMT_BITSTREAM: 174 /* TODO: need visit here when bit stream is supported */ 175 buffer_offset.yOffset = 176 src_buf->bit_stream[i].data_offset; 177 buffer_offset.totalSize = 178 src_buf->bit_stream[i].buf_size; 179 CDBG("%s: idx=%d, yOffset =%d, cbcrOffset =%d, totalSize = %d\n", 180 __func__, i, buffer_offset.yOffset, buffer_offset.cbcrOffset, buffer_offset.totalSize); 181 OMX_SetParameter(my_obj->omx_handle, buf_offset_idx, &buffer_offset); 182 break; 183 default: 184 break; 185 } 186 } 187 188 return rc; 189 } 190 191 /* TODO: needs revisit after omx lib supports multi src buffers */ 192 int32_t mm_jpeg_omx_config_port(mm_jpeg_obj* my_obj, src_image_buffer_info *src_buf, int port_idx) 193 { 194 int32_t rc = 0; 195 uint8_t i; 196 OMX_PARAM_PORTDEFINITIONTYPE input_port; 197 198 for (i = 0; i < src_buf->num_bufs; i++) { 199 memset(&input_port, 0, sizeof(input_port)); 200 input_port.nPortIndex = port_idx; 201 OMX_GetParameter(my_obj->omx_handle, OMX_IndexParamPortDefinition, &input_port); 202 input_port.format.image.nFrameWidth = src_buf->src_dim.width; 203 input_port.format.image.nFrameHeight =src_buf->src_dim.height; 204 input_port.format.image.nStride = src_buf->src_dim.width; 205 input_port.format.image.nSliceHeight = src_buf->src_dim.height; 206 switch (src_buf->img_fmt) { 207 case JPEG_SRC_IMAGE_FMT_YUV: 208 input_port.nBufferSize = src_buf->src_image[i].offset.frame_len; 209 break; 210 case JPEG_SRC_IMAGE_FMT_BITSTREAM: 211 input_port.nBufferSize = src_buf->bit_stream[i].buf_size; 212 break; 213 } 214 215 OMX_SetParameter(my_obj->omx_handle, OMX_IndexParamPortDefinition, &input_port); 216 } 217 218 return rc; 219 } 220 221 omx_jpeg_color_format map_jpeg_format(mm_jpeg_color_format color_fmt) 222 { 223 switch (color_fmt) { 224 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2: 225 return OMX_YCRCBLP_H2V2; 226 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2: 227 return OMX_YCBCRLP_H2V2; 228 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V1: 229 return OMX_YCRCBLP_H2V1; 230 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V1: 231 return OMX_YCBCRLP_H2V1; 232 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V2: 233 return OMX_YCRCBLP_H1V2; 234 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V2: 235 return OMX_YCBCRLP_H1V2; 236 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V1: 237 return OMX_YCRCBLP_H1V1; 238 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V1: 239 return OMX_YCBCRLP_H1V1; 240 case MM_JPEG_COLOR_FORMAT_RGB565: 241 return OMX_RGB565; 242 case MM_JPEG_COLOR_FORMAT_RGB888: 243 return OMX_RGB888; 244 case MM_JPEG_COLOR_FORMAT_RGBa: 245 return OMX_RGBa; 246 case MM_JPEG_COLOR_FORMAT_BITSTREAM: 247 /* TODO: need to change to new bitstream value once omx interface changes */ 248 return OMX_JPEG_BITSTREAM_H2V2; 249 default: 250 return OMX_JPEG_COLOR_FORMAT_MAX; 251 } 252 } 253 254 int32_t mm_jpeg_omx_config_user_preference(mm_jpeg_obj* my_obj, mm_jpeg_encode_job* job) 255 { 256 int32_t rc = 0; 257 OMX_INDEXTYPE user_pref_idx; 258 omx_jpeg_user_preferences user_preferences; 259 260 memset(&user_preferences, 0, sizeof(user_preferences)); 261 user_preferences.color_format = 262 map_jpeg_format(job->encode_parm.buf_info.src_imgs.src_img[JPEG_SRC_IMAGE_TYPE_MAIN].color_format); 263 if (job->encode_parm.buf_info.src_imgs.src_img_num > 1) { 264 user_preferences.thumbnail_color_format = 265 map_jpeg_format(job->encode_parm.buf_info.src_imgs.src_img[JPEG_SRC_IMAGE_TYPE_THUMB].color_format); 266 } 267 OMX_GetExtensionIndex(my_obj->omx_handle, 268 "omx.qcom.jpeg.exttype.user_preferences", 269 &user_pref_idx); 270 CDBG("%s:User Preferences: color_format %d, thumbnail_color_format = %d", 271 __func__, user_preferences.color_format, user_preferences.thumbnail_color_format); 272 OMX_SetParameter(my_obj->omx_handle, user_pref_idx, &user_preferences); 273 return rc; 274 } 275 276 int32_t mm_jpeg_omx_config_thumbnail(mm_jpeg_obj* my_obj, mm_jpeg_encode_job* job) 277 { 278 int32_t rc = -1; 279 OMX_INDEXTYPE thumb_idx, q_idx; 280 omx_jpeg_thumbnail thumbnail; 281 omx_jpeg_thumbnail_quality quality; 282 283 src_image_buffer_info *src_buf = 284 &(job->encode_parm.buf_info.src_imgs.src_img[JPEG_SRC_IMAGE_TYPE_THUMB]); 285 286 /* config port */ 287 rc = mm_jpeg_omx_config_port(my_obj, src_buf, INPUT_PORT_THUMBNAIL); 288 if (0 != rc) { 289 CDBG_ERROR("%s: config port failed", __func__); 290 return rc; 291 } 292 293 /* check crop boundary */ 294 if ((src_buf->crop.width == 0) || (src_buf->crop.height == 0) || 295 (src_buf->crop.width + src_buf->crop.offset_x > src_buf->src_dim.width) || 296 (src_buf->crop.height + src_buf->crop.offset_y > src_buf->src_dim.height)) { 297 CDBG_ERROR("%s: invalid crop boundary (%d, %d) offset (%d, %d) out of (%d, %d)", 298 __func__, 299 src_buf->crop.width, 300 src_buf->crop.height, 301 src_buf->crop.offset_x, 302 src_buf->crop.offset_y, 303 src_buf->src_dim.width, 304 src_buf->src_dim.height); 305 return rc; 306 } 307 308 memset(&thumbnail, 0, sizeof(thumbnail)); 309 310 /* thumbnail crop info */ 311 thumbnail.cropWidth = CEILING2(src_buf->crop.width); 312 thumbnail.cropHeight = CEILING2(src_buf->crop.height); 313 thumbnail.left = src_buf->crop.offset_x; 314 thumbnail.top = src_buf->crop.offset_y; 315 316 /* thumbnail output dimention */ 317 thumbnail.width = src_buf->out_dim.width; 318 thumbnail.height = src_buf->out_dim.height; 319 320 /* set scaling flag */ 321 if (thumbnail.left > 0 || thumbnail.top > 0 || 322 src_buf->crop.width != src_buf->out_dim.width || 323 src_buf->crop.height != src_buf->out_dim.height) { 324 thumbnail.scaling = 1; 325 } 326 327 /* set omx thumbnail info */ 328 OMX_GetExtensionIndex(my_obj->omx_handle, "omx.qcom.jpeg.exttype.thumbnail", &thumb_idx); 329 OMX_SetParameter(my_obj->omx_handle, thumb_idx, &thumbnail); 330 331 OMX_GetExtensionIndex(my_obj->omx_handle, "omx.qcom.jpeg.exttype.thumbnail_quality", &q_idx); 332 OMX_GetParameter(my_obj->omx_handle, q_idx, &quality); 333 quality.nQFactor = src_buf->quality; 334 OMX_SetParameter(my_obj->omx_handle, q_idx, &quality); 335 336 rc = 0; 337 return rc; 338 } 339 340 int32_t mm_jpeg_omx_config_main_crop(mm_jpeg_obj* my_obj, src_image_buffer_info *src_buf) 341 { 342 int32_t rc = 0; 343 OMX_CONFIG_RECTTYPE rect_type; 344 345 /* error check first */ 346 if (src_buf->crop.width + src_buf->crop.offset_x > src_buf->src_dim.width || 347 src_buf->crop.height + src_buf->crop.offset_y > src_buf->src_dim.height) { 348 CDBG_ERROR("%s: invalid crop boundary (%d, %d) out of (%d, %d)", __func__, 349 src_buf->crop.width + src_buf->crop.offset_x, 350 src_buf->crop.height + src_buf->crop.offset_y, 351 src_buf->src_dim.width, 352 src_buf->src_dim.height); 353 return -1; 354 } 355 356 if (src_buf->crop.width && src_buf->crop.width) { 357 /* Scaler information */ 358 memset(&rect_type, 0, sizeof(rect_type)); 359 rect_type.nWidth = CEILING2(src_buf->crop.width); 360 rect_type.nHeight = CEILING2(src_buf->crop.width); 361 rect_type.nLeft = src_buf->crop.offset_x; 362 rect_type.nTop = src_buf->crop.offset_y; 363 rect_type.nPortIndex = OUTPUT_PORT; 364 OMX_SetConfig(my_obj->omx_handle, OMX_IndexConfigCommonInputCrop, &rect_type); 365 366 if (src_buf->out_dim.width && src_buf->out_dim.height) { 367 memset(&rect_type, 0, sizeof(rect_type)); 368 rect_type.nWidth = src_buf->out_dim.width; 369 rect_type.nHeight = src_buf->out_dim.height; 370 rect_type.nPortIndex = OUTPUT_PORT; 371 OMX_SetConfig(my_obj->omx_handle, OMX_IndexConfigCommonOutputCrop, &rect_type); 372 } 373 374 } else { 375 CDBG_ERROR("%s: There is no main image scaling information", __func__); 376 rc = -1; 377 } 378 379 return rc; 380 } 381 382 int32_t mm_jpeg_omx_config_main(mm_jpeg_obj* my_obj, mm_jpeg_encode_job* job) 383 { 384 int32_t rc = 0; 385 src_image_buffer_info *src_buf = 386 &(job->encode_parm.buf_info.src_imgs.src_img[JPEG_SRC_IMAGE_TYPE_MAIN]); 387 OMX_IMAGE_PARAM_QFACTORTYPE q_factor; 388 389 /* config port */ 390 rc = mm_jpeg_omx_config_port(my_obj, src_buf, INPUT_PORT_MAIN); 391 if (0 != rc) { 392 CDBG_ERROR("%s: config port failed", __func__); 393 return rc; 394 } 395 396 /* config buffer offset */ 397 rc = mm_jpeg_omx_config_main_buffer_offset(my_obj, src_buf); 398 if (0 != rc) { 399 CDBG_ERROR("%s: config buffer offset failed", __func__); 400 return rc; 401 } 402 403 /* config crop */ 404 rc = mm_jpeg_omx_config_main_crop(my_obj, src_buf); 405 if (0 != rc) { 406 CDBG_ERROR("%s: config crop failed", __func__); 407 return rc; 408 } 409 410 /* set quality */ 411 memset(&q_factor, 0, sizeof(q_factor)); 412 q_factor.nPortIndex = INPUT_PORT_MAIN; 413 OMX_GetParameter(my_obj->omx_handle, OMX_IndexParamQFactor, &q_factor); 414 q_factor.nQFactor = src_buf->quality; 415 OMX_SetParameter(my_obj->omx_handle, OMX_IndexParamQFactor, &q_factor); 416 417 return rc; 418 } 419 420 int32_t mm_jpeg_omx_config_common(mm_jpeg_obj* my_obj, mm_jpeg_encode_job* job) 421 { 422 int32_t rc; 423 int i; 424 OMX_INDEXTYPE exif_idx; 425 omx_jpeg_exif_info_tag tag; 426 OMX_CONFIG_ROTATIONTYPE rotate; 427 428 /* config user prefernces */ 429 rc = mm_jpeg_omx_config_user_preference(my_obj, job); 430 if (0 != rc) { 431 CDBG_ERROR("%s: config user preferences failed", __func__); 432 return rc; 433 } 434 435 /* set rotation */ 436 memset(&rotate, 0, sizeof(rotate)); 437 rotate.nPortIndex = OUTPUT_PORT; 438 rotate.nRotation = job->encode_parm.rotation; 439 OMX_SetConfig(my_obj->omx_handle, OMX_IndexConfigCommonRotate, &rotate); 440 CDBG("%s: Set rotation to %d\n", __func__, job->encode_parm.rotation); 441 442 /* set exif tags */ 443 OMX_GetExtensionIndex(my_obj->omx_handle, "omx.qcom.jpeg.exttype.exif", &exif_idx); 444 for(i = 0; i < job->encode_parm.exif_numEntries; i++) { 445 memcpy(&tag, job->encode_parm.exif_data + i, sizeof(omx_jpeg_exif_info_tag)); 446 OMX_SetParameter(my_obj->omx_handle, exif_idx, &tag); 447 } 448 449 return rc; 450 } 451 452 int32_t mm_jpeg_omx_use_buf(mm_jpeg_obj* my_obj, 453 src_image_buffer_info *src_buf, 454 mm_jpeg_omx_src_buf* omx_src_buf, 455 int port_idx) 456 { 457 int32_t rc = 0; 458 uint8_t i; 459 omx_jpeg_pmem_info pmem_info; 460 461 omx_src_buf->num_bufs = src_buf->num_bufs; 462 for (i = 0; i < src_buf->num_bufs; i++) { 463 memset(&pmem_info, 0, sizeof(pmem_info)); 464 switch (src_buf->img_fmt) { 465 case JPEG_SRC_IMAGE_FMT_YUV: 466 pmem_info.fd = src_buf->src_image[i].fd; 467 pmem_info.offset = 0; 468 omx_src_buf->bufs[i].portIdx = port_idx; 469 OMX_UseBuffer(my_obj->omx_handle, 470 &omx_src_buf->bufs[i].buf_header, 471 port_idx, 472 &pmem_info, 473 src_buf->src_image[i].offset.frame_len, 474 (void *)src_buf->src_image[i].buf_vaddr); 475 break; 476 case JPEG_SRC_IMAGE_FMT_BITSTREAM: 477 pmem_info.fd = src_buf->bit_stream[i].fd; 478 pmem_info.offset = 0; 479 omx_src_buf->bufs[i].portIdx = port_idx; 480 OMX_UseBuffer(my_obj->omx_handle, 481 &omx_src_buf->bufs[i].buf_header, 482 port_idx, 483 &pmem_info, 484 src_buf->bit_stream[i].buf_size, 485 (void *)src_buf->bit_stream[i].buf_vaddr); 486 break; 487 default: 488 rc = -1; 489 break; 490 } 491 } 492 493 return rc; 494 } 495 496 int32_t mm_jpeg_omx_encode(mm_jpeg_obj* my_obj, mm_jpeg_job_entry* job_entry) 497 { 498 int32_t rc = 0; 499 uint8_t i; 500 mm_jpeg_encode_job* job = &job_entry->job.encode_job; 501 uint8_t has_thumbnail = job->encode_parm.buf_info.src_imgs.src_img_num > 1? 1 : 0; 502 src_image_buffer_info *src_buf[JPEG_SRC_IMAGE_TYPE_MAX]; 503 mm_jpeg_omx_src_buf *omx_src_buf[JPEG_SRC_IMAGE_TYPE_MAX]; 504 505 /* config main img */ 506 rc = mm_jpeg_omx_config_main(my_obj, job); 507 if (0 != rc) { 508 CDBG_ERROR("%s: config main img failed", __func__); 509 return rc; 510 } 511 512 /* config thumbnail */ 513 rc = mm_jpeg_omx_config_thumbnail(my_obj, job); 514 if (0 != rc) { 515 CDBG_ERROR("%s: config thumbnail img failed", __func__); 516 return rc; 517 } 518 519 /* common config */ 520 rc = mm_jpeg_omx_config_common(my_obj, job); 521 if (0 != rc) { 522 CDBG_ERROR("%s: config common failed", __func__); 523 return rc; 524 } 525 526 /* config input omx buffer for main input */ 527 src_buf[JPEG_SRC_IMAGE_TYPE_MAIN] = &(job->encode_parm.buf_info.src_imgs.src_img[JPEG_SRC_IMAGE_TYPE_MAIN]); 528 omx_src_buf[JPEG_SRC_IMAGE_TYPE_MAIN] = &job_entry->src_bufs[JPEG_SRC_IMAGE_TYPE_MAIN]; 529 rc = mm_jpeg_omx_use_buf(my_obj, 530 src_buf[JPEG_SRC_IMAGE_TYPE_MAIN], 531 omx_src_buf[JPEG_SRC_IMAGE_TYPE_MAIN], 532 INPUT_PORT_MAIN); 533 if (0 != rc) { 534 CDBG_ERROR("%s: config main input omx buffer failed", __func__); 535 return rc; 536 } 537 538 /* config input omx buffer for thumbnail input if there is thumbnail */ 539 if (has_thumbnail) { 540 src_buf[JPEG_SRC_IMAGE_TYPE_THUMB] = &(job->encode_parm.buf_info.src_imgs.src_img[JPEG_SRC_IMAGE_TYPE_THUMB]); 541 omx_src_buf[JPEG_SRC_IMAGE_TYPE_THUMB] = &job_entry->src_bufs[JPEG_SRC_IMAGE_TYPE_THUMB]; 542 rc = mm_jpeg_omx_use_buf(my_obj, 543 src_buf[JPEG_SRC_IMAGE_TYPE_THUMB], 544 omx_src_buf[JPEG_SRC_IMAGE_TYPE_THUMB], 545 INPUT_PORT_THUMBNAIL); 546 if (0 != rc) { 547 CDBG_ERROR("%s: config thumbnail input omx buffer failed", __func__); 548 return rc; 549 } 550 } 551 552 /* config output omx buffer */ 553 job_entry->sink_buf.portIdx = OUTPUT_PORT; 554 OMX_UseBuffer(my_obj->omx_handle, 555 &job_entry->sink_buf.buf_header, 556 job_entry->sink_buf.portIdx, 557 NULL, 558 job->encode_parm.buf_info.sink_img.buf_len, 559 (void *)job->encode_parm.buf_info.sink_img.buf_vaddr); 560 561 /* wait for OMX state ready */ 562 mm_jpeg_job_wait_for_cmd_complete(my_obj, OMX_CommandStateSet, OMX_StateIdle); 563 CDBG("%s: State changed to OMX_StateIdle\n", __func__); 564 565 /* start OMX encoding by sending executing cmd */ 566 OMX_SendCommand(my_obj->omx_handle, OMX_CommandStateSet, OMX_StateExecuting, NULL); 567 mm_jpeg_job_wait_for_cmd_complete(my_obj, OMX_CommandStateSet, OMX_StateExecuting); 568 569 /* start input fedding and output writing */ 570 for (i = 0; i < job_entry->src_bufs[JPEG_SRC_IMAGE_TYPE_MAIN].num_bufs; i++) { 571 OMX_EmptyThisBuffer(my_obj->omx_handle, 572 job_entry->src_bufs[JPEG_SRC_IMAGE_TYPE_MAIN].bufs[i].buf_header); 573 } 574 if (has_thumbnail) { 575 for (i = 0; i < job_entry->src_bufs[JPEG_SRC_IMAGE_TYPE_THUMB].num_bufs; i++) { 576 OMX_EmptyThisBuffer(my_obj->omx_handle, 577 job_entry->src_bufs[JPEG_SRC_IMAGE_TYPE_THUMB].bufs[i].buf_header); 578 } 579 } 580 OMX_FillThisBuffer(my_obj->omx_handle, job_entry->sink_buf.buf_header); 581 582 return rc; 583 } 584 585 static void *mm_jpeg_notify_thread(void *data) 586 { 587 mm_jpeg_job_q_node_t* job_node = (mm_jpeg_job_q_node_t *)data; 588 mm_jpeg_job_entry * job_entry = &job_node->entry; 589 mm_jpeg_obj* my_obj = (mm_jpeg_obj *)job_entry->jpeg_obj; 590 void* node = NULL; 591 int32_t rc = 0; 592 593 if (NULL == my_obj) { 594 CDBG_ERROR("%s: jpeg obj is NULL", __func__); 595 return NULL; 596 } 597 598 /* Add to cb queue */ 599 rc = mm_jpeg_queue_enq(&my_obj->cb_q, data); 600 if (0 != rc) { 601 CDBG_ERROR("%s: enqueue into cb_q failed", __func__); 602 return NULL; 603 } 604 605 /* call cb */ 606 if (NULL != job_entry->job.encode_job.jpeg_cb) { 607 /* has callback, send CB */ 608 job_entry->job.encode_job.jpeg_cb(job_entry->job_status, 609 job_entry->thumbnail_dropped, 610 job_entry->client_hdl, 611 job_entry->jobId, 612 job_entry->job.encode_job.encode_parm.buf_info.sink_img.buf_vaddr, 613 job_entry->jpeg_size, 614 job_entry->job.encode_job.userdata); 615 } else { 616 CDBG_ERROR("%s: no cb provided, no action", __func__); 617 } 618 619 /* Remove from cb queue */ 620 node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->cb_q, job_entry->jobId); 621 if (NULL != node) { 622 free(node); 623 } 624 625 return NULL; 626 } 627 628 /* process encoding job */ 629 int32_t mm_jpeg_process_encoding_job(mm_jpeg_obj *my_obj, mm_jpeg_job_q_node_t* job_node) 630 { 631 int32_t rc = 0; 632 mm_jpeg_job_entry* job_entry = &job_node->entry; 633 634 /* call OMX_Encode */ 635 rc = mm_jpeg_omx_encode(my_obj, job_entry); 636 if (0 == rc) { 637 /* sent encode cmd to OMX, queue job into ongoing queue */ 638 rc = mm_jpeg_queue_enq(&my_obj->ongoing_job_q, job_node); 639 } else { 640 /* OMX encode failed, notify error through callback */ 641 job_entry->job_status = JPEG_JOB_STATUS_ERROR; 642 if (NULL != job_entry->job.encode_job.jpeg_cb) { 643 /* has callback, create a thread to send CB */ 644 pthread_create(&job_entry->cb_pid, 645 NULL, 646 mm_jpeg_notify_thread, 647 (void *)job_node); 648 649 } else { 650 CDBG_ERROR("%s: no cb provided, return here", __func__); 651 free(job_node); 652 } 653 } 654 655 return rc; 656 } 657 /* process job (encoding/decoding) */ 658 int32_t mm_jpeg_process_job(mm_jpeg_obj *my_obj, mm_jpeg_job_q_node_t* job_node) 659 { 660 int32_t rc = 0; 661 662 switch (job_node->entry.job.job_type) { 663 case JPEG_JOB_TYPE_ENCODE: 664 rc = mm_jpeg_process_encoding_job(my_obj, job_node); 665 break; 666 default: 667 CDBG_ERROR("%s: job type not supported (%d)", 668 __func__, job_node->entry.job.job_type); 669 rc = -1; 670 break; 671 } 672 673 return rc; 674 } 675 676 static void *mm_jpeg_jobmgr_thread(void *data) 677 { 678 int rc = 0; 679 int running = 1; 680 uint32_t num_ongoing_jobs = 0; 681 mm_jpeg_obj *my_obj = (mm_jpeg_obj*)data; 682 mm_jpeg_job_cmd_thread_t *cmd_thread = 683 (mm_jpeg_job_cmd_thread_t *)data; 684 mm_jpeg_job_q_node_t* node = NULL; 685 686 do { 687 do { 688 rc = sem_wait(&cmd_thread->job_sem); 689 if (rc != 0 && errno != EINVAL) { 690 CDBG_ERROR("%s: sem_wait error (%s)", 691 __func__, strerror(errno)); 692 return NULL; 693 } 694 } while (rc != 0); 695 696 /* check ongoing q size */ 697 num_ongoing_jobs = mm_jpeg_queue_get_size(&my_obj->ongoing_job_q); 698 if (num_ongoing_jobs >= NUM_MAX_JPEG_CNCURRENT_JOBS) { 699 continue; 700 } 701 702 pthread_mutex_lock(&my_obj->job_lock); 703 /* can go ahead with new work */ 704 node = (mm_jpeg_job_q_node_t*)mm_jpeg_queue_deq(&cmd_thread->job_queue); 705 if (node != NULL) { 706 switch (node->type) { 707 case MM_JPEG_CMD_TYPE_JOB: 708 rc = mm_jpeg_process_job(my_obj, node); 709 if (0 != rc) { 710 /* free node in error case */ 711 free(node); 712 } 713 break; 714 case MM_JPEG_CMD_TYPE_EXIT: 715 default: 716 /* free node */ 717 free(node); 718 /* set running flag to false */ 719 running = 0; 720 break; 721 } 722 } 723 pthread_mutex_unlock(&my_obj->job_lock); 724 725 } while (running); 726 return NULL; 727 } 728 729 int32_t mm_jpeg_jobmgr_thread_launch(mm_jpeg_obj * my_obj) 730 { 731 int32_t rc = 0; 732 mm_jpeg_job_cmd_thread_t * job_mgr = &my_obj->job_mgr; 733 734 sem_init(&job_mgr->job_sem, 0, 0); 735 mm_jpeg_queue_init(&job_mgr->job_queue); 736 737 /* launch the thread */ 738 pthread_create(&job_mgr->pid, 739 NULL, 740 mm_jpeg_jobmgr_thread, 741 (void *)my_obj); 742 return rc; 743 } 744 745 int32_t mm_jpeg_jobmgr_thread_release(mm_jpeg_obj * my_obj) 746 { 747 int32_t rc = 0; 748 mm_jpeg_job_cmd_thread_t * cmd_thread = &my_obj->job_mgr; 749 mm_jpeg_job_q_node_t* node = 750 (mm_jpeg_job_q_node_t *)malloc(sizeof(mm_jpeg_job_q_node_t)); 751 if (NULL == node) { 752 CDBG_ERROR("%s: No memory for mm_jpeg_job_q_node_t", __func__); 753 return -1; 754 } 755 756 memset(node, 0, sizeof(mm_jpeg_job_q_node_t)); 757 node->type = MM_JPEG_CMD_TYPE_EXIT; 758 759 mm_jpeg_queue_enq(&cmd_thread->job_queue, node); 760 sem_post(&cmd_thread->job_sem); 761 762 /* wait until cmd thread exits */ 763 if (pthread_join(cmd_thread->pid, NULL) != 0) { 764 CDBG("%s: pthread dead already\n", __func__); 765 } 766 mm_jpeg_queue_deinit(&cmd_thread->job_queue); 767 768 sem_destroy(&cmd_thread->job_sem); 769 memset(cmd_thread, 0, sizeof(mm_jpeg_job_cmd_thread_t)); 770 return rc; 771 } 772 773 int32_t mm_jpeg_init(mm_jpeg_obj *my_obj) 774 { 775 int32_t rc = 0; 776 777 /* init locks */ 778 pthread_mutex_init(&my_obj->job_lock, NULL); 779 pthread_mutex_init(&my_obj->omx_evt_lock, NULL); 780 pthread_cond_init(&my_obj->omx_evt_cond, NULL); 781 782 /* init ongoing job queue */ 783 rc = mm_jpeg_queue_init(&my_obj->ongoing_job_q); 784 785 /* init job semaphore and launch jobmgr thread */ 786 CDBG("%s : Launch jobmgr thread",__func__); 787 rc = mm_jpeg_jobmgr_thread_launch(my_obj); 788 789 /* load OMX */ 790 rc = mm_jpeg_omx_load(my_obj); 791 if (0 != rc) { 792 /* roll back in error case */ 793 mm_jpeg_jobmgr_thread_release(my_obj); 794 mm_jpeg_queue_deinit(&my_obj->ongoing_job_q); 795 pthread_mutex_destroy(&my_obj->job_lock); 796 pthread_mutex_destroy(&my_obj->omx_evt_lock); 797 pthread_cond_destroy(&my_obj->omx_evt_cond); 798 } 799 800 return rc; 801 } 802 803 int32_t mm_jpeg_deinit(mm_jpeg_obj *my_obj) 804 { 805 int32_t rc = 0; 806 807 /* unload OMX engine */ 808 rc = mm_jpeg_omx_unload(my_obj); 809 810 /* release jobmgr thread */ 811 rc = mm_jpeg_jobmgr_thread_release(my_obj); 812 813 /* deinit ongoing job queue */ 814 rc = mm_jpeg_queue_deinit(&my_obj->ongoing_job_q); 815 816 /* destroy locks */ 817 pthread_mutex_destroy(&my_obj->job_lock); 818 pthread_mutex_destroy(&my_obj->omx_evt_lock); 819 pthread_cond_destroy(&my_obj->omx_evt_cond); 820 821 return rc; 822 } 823 824 uint32_t mm_jpeg_new_client(mm_jpeg_obj *my_obj) 825 { 826 uint32_t client_hdl = 0; 827 uint8_t idx; 828 829 if (my_obj->num_clients >= MAX_JPEG_CLIENT_NUM) { 830 CDBG_ERROR("%s: num of clients reached limit", __func__); 831 return client_hdl; 832 } 833 834 for (idx = 0; idx < MAX_JPEG_CLIENT_NUM; idx++) { 835 if (0 == my_obj->clnt_mgr[idx].is_used) { 836 break; 837 } 838 } 839 840 if (idx < MAX_JPEG_CLIENT_NUM) { 841 /* client entry avail */ 842 /* generate client handler by index */ 843 client_hdl = mm_jpeg_util_generate_handler(idx); 844 845 /* update client entry */ 846 my_obj->clnt_mgr[idx].is_used = 1; 847 my_obj->clnt_mgr[idx].client_handle = client_hdl; 848 849 /* increse client count */ 850 my_obj->num_clients++; 851 } 852 853 return client_hdl; 854 } 855 856 int32_t mm_jpeg_start_job(mm_jpeg_obj *my_obj, 857 uint32_t client_hdl, 858 mm_jpeg_job* job, 859 uint32_t* jobId) 860 { 861 int32_t rc = -1; 862 uint8_t clnt_idx = 0; 863 uint32_t job_id = 0; 864 mm_jpeg_job_q_node_t* node = NULL; 865 866 *jobId = 0; 867 868 /* check if valid client */ 869 clnt_idx = mm_jpeg_util_get_index_by_handler(client_hdl); 870 if (clnt_idx >= MAX_JPEG_CLIENT_NUM ) { 871 CDBG_ERROR("%s: invalid client with handler (%d)", __func__, client_hdl); 872 return rc; 873 } 874 875 /* generate client handler by index */ 876 job_id = mm_jpeg_util_generate_handler(clnt_idx); 877 878 /* enqueue new job into todo job queue */ 879 node = (mm_jpeg_job_q_node_t *)malloc(sizeof(mm_jpeg_job_q_node_t)); 880 if (NULL == node) { 881 CDBG_ERROR("%s: No memory for mm_jpeg_job_q_node_t", __func__); 882 return -rc; 883 } 884 885 memset(node, 0, sizeof(mm_jpeg_job_q_node_t)); 886 node->type = MM_JPEG_CMD_TYPE_JOB; 887 node->entry.client_hdl = client_hdl; 888 node->entry.jobId = job_id; 889 memcpy(&node->entry.job, job, sizeof(mm_jpeg_job)); 890 node->entry.jpeg_obj = (void*)my_obj; /* save a ptr to jpeg_obj */ 891 892 rc = mm_jpeg_queue_enq(&my_obj->job_mgr.job_queue, node); 893 if (0 == rc) { 894 sem_post(&my_obj->job_mgr.job_sem); 895 *jobId = job_id; 896 } 897 898 return rc; 899 } 900 901 int32_t mm_jpeg_abort_job(mm_jpeg_obj *my_obj, 902 uint32_t client_hdl, 903 uint32_t jobId) 904 { 905 int32_t rc = -1; 906 uint8_t clnt_idx = 0; 907 void * node = NULL; 908 mm_jpeg_job_entry* job_entry = NULL; 909 910 /* check if valid client */ 911 clnt_idx = mm_jpeg_util_get_index_by_handler(client_hdl); 912 if (clnt_idx >= MAX_JPEG_CLIENT_NUM ) { 913 CDBG_ERROR("%s: invalid client with handler (%d)", __func__, client_hdl); 914 return rc; 915 } 916 917 pthread_mutex_lock(&my_obj->job_lock); 918 919 /* abort job if in ongoing queue */ 920 node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->ongoing_job_q, jobId); 921 if (NULL != node) { 922 /* find job that is OMX ongoing, ask OMX to abort the job */ 923 job_entry = &(((mm_jpeg_job_q_node_t *)node)->entry); 924 rc = mm_jpeg_omx_abort_job(my_obj, job_entry); 925 free(node); 926 goto abort_done; 927 } 928 929 /* abort job if in todo queue */ 930 node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->job_mgr.job_queue, jobId); 931 if (NULL != node) { 932 /* simply delete it */ 933 free(node); 934 goto abort_done; 935 } 936 937 /* abort job if in cb queue */ 938 node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->cb_q, jobId); 939 if (NULL != node) { 940 /* join cb thread */ 941 job_entry = &(((mm_jpeg_job_q_node_t *)node)->entry); 942 if (pthread_join(job_entry->cb_pid, NULL) != 0) { 943 CDBG("%s: pthread dead already\n", __func__); 944 } 945 free(node); 946 } 947 948 abort_done: 949 pthread_mutex_unlock(&my_obj->job_lock); 950 951 /* wake up jobMgr thread to work on new job if there is any */ 952 sem_post(&my_obj->job_mgr.job_sem); 953 954 return rc; 955 } 956 957 int32_t mm_jpeg_close(mm_jpeg_obj *my_obj, uint32_t client_hdl) 958 { 959 int32_t rc = -1; 960 uint8_t clnt_idx = 0; 961 void* node = NULL; 962 mm_jpeg_job_entry* job_entry = NULL; 963 964 /* check if valid client */ 965 clnt_idx = mm_jpeg_util_get_index_by_handler(client_hdl); 966 if (clnt_idx >= MAX_JPEG_CLIENT_NUM ) { 967 CDBG_ERROR("%s: invalid client with handler (%d)", __func__, client_hdl); 968 return rc; 969 } 970 971 /* abort all jobs from the client */ 972 pthread_mutex_lock(&my_obj->job_lock); 973 974 /* abort job if in ongoing queue */ 975 node = mm_jpeg_queue_remove_job_by_client_id(&my_obj->ongoing_job_q, client_hdl); 976 while (NULL != node) { 977 /* find job that is OMX ongoing, ask OMX to abort the job */ 978 job_entry = &(((mm_jpeg_job_q_node_t *)node)->entry); 979 rc = mm_jpeg_omx_abort_job(my_obj, job_entry); 980 free(node); 981 982 /* find next job from ongoing queue that belongs to this client */ 983 node = mm_jpeg_queue_remove_job_by_client_id(&my_obj->ongoing_job_q, client_hdl); 984 } 985 986 /* abort job if in todo queue */ 987 node = mm_jpeg_queue_remove_job_by_client_id(&my_obj->job_mgr.job_queue, client_hdl); 988 while (NULL != node) { 989 /* simply delete the job if in todo queue */ 990 free(node); 991 992 /* find next job from todo queue that belongs to this client */ 993 node = mm_jpeg_queue_remove_job_by_client_id(&my_obj->job_mgr.job_queue, client_hdl); 994 } 995 996 /* abort job if in cb queue */ 997 node = mm_jpeg_queue_remove_job_by_client_id(&my_obj->cb_q, client_hdl); 998 while (NULL != node) { 999 /* join cb thread */ 1000 job_entry = &(((mm_jpeg_job_q_node_t *)node)->entry); 1001 if (pthread_join(job_entry->cb_pid, NULL) != 0) { 1002 CDBG("%s: pthread dead already\n", __func__); 1003 } 1004 free(node); 1005 1006 /* find next job from cb queue that belongs to this client */ 1007 node = mm_jpeg_queue_remove_job_by_client_id(&my_obj->cb_q, client_hdl); 1008 } 1009 1010 pthread_mutex_unlock(&my_obj->job_lock); 1011 1012 /* invalidate client entry */ 1013 memset(&my_obj->clnt_mgr[clnt_idx], 0, sizeof(mm_jpeg_client_t)); 1014 1015 return rc; 1016 } 1017 1018 void mm_jpeg_job_wait_for_event(mm_jpeg_obj *my_obj, uint32_t evt_mask) 1019 { 1020 pthread_mutex_lock(&my_obj->omx_evt_lock); 1021 while (!(my_obj->omx_evt_rcvd.evt & evt_mask)) { 1022 pthread_cond_wait(&my_obj->omx_evt_cond, &my_obj->omx_evt_lock); 1023 } 1024 CDBG("%s:done", __func__); 1025 pthread_mutex_unlock(&my_obj->omx_evt_lock); 1026 } 1027 1028 void mm_jpeg_job_wait_for_cmd_complete(mm_jpeg_obj *my_obj, 1029 int cmd, 1030 int status) 1031 { 1032 pthread_mutex_lock(&my_obj->omx_evt_lock); 1033 while (!((my_obj->omx_evt_rcvd.evt & MM_JPEG_EVENT_MASK_CMD_COMPLETE) && 1034 (my_obj->omx_evt_rcvd.omx_value1 == cmd) && 1035 (my_obj->omx_evt_rcvd.omx_value2 == status))) { 1036 pthread_cond_wait(&my_obj->omx_evt_cond, &my_obj->omx_evt_lock); 1037 } 1038 CDBG("%s:done", __func__); 1039 pthread_mutex_unlock(&my_obj->omx_evt_lock); 1040 } 1041 1042 OMX_ERRORTYPE mm_jpeg_etbdone(OMX_HANDLETYPE hComponent, 1043 OMX_PTR pAppData, 1044 OMX_BUFFERHEADERTYPE* pBuffer) 1045 { 1046 /* no process needed for etbdone, return here */ 1047 return 0; 1048 } 1049 1050 OMX_ERRORTYPE mm_jpeg_ftbdone(OMX_HANDLETYPE hComponent, 1051 OMX_PTR pAppData, 1052 OMX_BUFFERHEADERTYPE* pBuffer) 1053 { 1054 int rc = 0; 1055 void* node = NULL; 1056 mm_jpeg_job_entry* job_entry = NULL; 1057 mm_jpeg_obj * my_obj = (mm_jpeg_obj*)pAppData; 1058 1059 if (NULL != my_obj) { 1060 CDBG_ERROR("%s: pAppData is NULL, return here", __func__); 1061 return rc; 1062 } 1063 1064 /* signal JPEG_DONE event */ 1065 pthread_mutex_lock(&my_obj->omx_evt_lock); 1066 my_obj->omx_evt_rcvd.evt = MM_JPEG_EVENT_MASK_JPEG_DONE; 1067 pthread_cond_signal(&my_obj->omx_evt_cond); 1068 pthread_mutex_unlock(&my_obj->omx_evt_lock); 1069 1070 /* If OMX can support multi encoding, it should provide a way to pass jobID. 1071 * then we can find job by jobID from ongoing queue. 1072 * For now, since OMX only support one job per time, we simply dequeue it. */ 1073 pthread_mutex_lock(&my_obj->job_lock); 1074 node = mm_jpeg_queue_deq(&my_obj->ongoing_job_q); 1075 if (NULL != node) { 1076 job_entry = &(((mm_jpeg_job_q_node_t *)node)->entry);; 1077 /* find job that is OMX ongoing */ 1078 job_entry->jpeg_size = pBuffer->nFilledLen; 1079 job_entry->job_status = JPEG_JOB_STATUS_DONE; 1080 CDBG("%s:filled len = %u, status = %d", 1081 __func__, job_entry->jpeg_size, job_entry->job_status); 1082 1083 if (NULL != job_entry->job.encode_job.jpeg_cb) { 1084 /* has callback, create a thread to send CB */ 1085 pthread_create(&job_entry->cb_pid, 1086 NULL, 1087 mm_jpeg_notify_thread, 1088 node); 1089 1090 } else { 1091 CDBG_ERROR("%s: no cb provided, return here", __func__); 1092 free(node); 1093 } 1094 } 1095 pthread_mutex_unlock(&my_obj->job_lock); 1096 1097 /* Wake up jobMgr thread to work on next job if there is any */ 1098 sem_post(&my_obj->job_mgr.job_sem); 1099 1100 return rc; 1101 } 1102 1103 OMX_ERRORTYPE mm_jpeg_handle_omx_event(OMX_HANDLETYPE hComponent, 1104 OMX_PTR pAppData, 1105 OMX_EVENTTYPE eEvent, 1106 OMX_U32 nData1, 1107 OMX_U32 nData2, 1108 OMX_PTR pEventData) 1109 { 1110 int rc = 0; 1111 void* node = NULL; 1112 mm_jpeg_job_entry* job_entry = NULL; 1113 mm_jpeg_obj * my_obj = (mm_jpeg_obj*)pAppData; 1114 uint32_t jobId = 0; 1115 1116 if (NULL != my_obj) { 1117 CDBG_ERROR("%s: pAppData is NULL, return here", __func__); 1118 return rc; 1119 } 1120 1121 /* signal event */ 1122 switch (eEvent) { 1123 case OMX_EVENT_JPEG_ABORT: 1124 { 1125 /* signal error evt */ 1126 pthread_mutex_lock(&my_obj->omx_evt_lock); 1127 my_obj->omx_evt_rcvd.evt = MM_JPEG_EVENT_MASK_JPEG_ABORT; 1128 pthread_cond_signal(&my_obj->omx_evt_cond); 1129 pthread_mutex_unlock(&my_obj->omx_evt_lock); 1130 } 1131 break; 1132 case OMX_EventError: 1133 { 1134 switch (nData1) { 1135 case OMX_EVENT_THUMBNAIL_DROPPED: 1136 { 1137 uint8_t thumbnail_dropped_flag = 1; 1138 mm_jpeg_queue_update_flag(&my_obj->ongoing_job_q, 1139 jobId, 1140 thumbnail_dropped_flag); 1141 } 1142 break; 1143 case OMX_EVENT_JPEG_ERROR: 1144 { 1145 /* signal error evt */ 1146 pthread_mutex_lock(&my_obj->omx_evt_lock); 1147 my_obj->omx_evt_rcvd.evt = MM_JPEG_EVENT_MASK_JPEG_ERROR; 1148 pthread_cond_signal(&my_obj->omx_evt_cond); 1149 pthread_mutex_unlock(&my_obj->omx_evt_lock); 1150 1151 /* send CB for error case */ 1152 /* If OMX can support multi encoding, it should provide a way to pass jobID. 1153 * then we can find job by jobID from ongoing queue. 1154 * For now, since OMX only support one job per time, we simply dequeue it. */ 1155 pthread_mutex_lock(&my_obj->job_lock); 1156 node = mm_jpeg_queue_deq(&my_obj->ongoing_job_q); 1157 if (NULL != node) { 1158 job_entry = &(((mm_jpeg_job_q_node_t *)node)->entry);; 1159 1160 /* find job that is OMX ongoing */ 1161 job_entry->job_status = JPEG_JOB_STATUS_ERROR; 1162 if (NULL != job_entry->job.encode_job.jpeg_cb) { 1163 /* has callback, create a thread to send CB */ 1164 pthread_create(&job_entry->cb_pid, 1165 NULL, 1166 mm_jpeg_notify_thread, 1167 node); 1168 1169 } else { 1170 CDBG_ERROR("%s: no cb provided, return here", __func__); 1171 free(node); 1172 } 1173 } 1174 pthread_mutex_unlock(&my_obj->job_lock); 1175 1176 /* Wake up jobMgr thread to work on next job if there is any */ 1177 sem_post(&my_obj->job_mgr.job_sem); 1178 } 1179 break; 1180 default: 1181 break; 1182 } 1183 } 1184 break; 1185 case OMX_EventCmdComplete: 1186 { 1187 /* signal cmd complete evt */ 1188 pthread_mutex_lock(&my_obj->omx_evt_lock); 1189 my_obj->omx_evt_rcvd.evt = MM_JPEG_EVENT_MASK_CMD_COMPLETE; 1190 my_obj->omx_evt_rcvd.omx_value1 = nData1; 1191 my_obj->omx_evt_rcvd.omx_value2 = nData2; 1192 pthread_cond_signal(&my_obj->omx_evt_cond); 1193 pthread_mutex_unlock(&my_obj->omx_evt_lock); 1194 } 1195 break; 1196 default: 1197 break; 1198 } 1199 1200 return rc; 1201 } 1202 1203 /* remove the first job from the queue with matching client handle */ 1204 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_client_id(mm_jpeg_queue_t* queue, uint32_t client_hdl) 1205 { 1206 mm_jpeg_q_node_t* node = NULL; 1207 mm_jpeg_job_q_node_t* data = NULL; 1208 mm_jpeg_job_q_node_t* job_node = NULL; 1209 struct cam_list *head = NULL; 1210 struct cam_list *pos = NULL; 1211 1212 pthread_mutex_lock(&queue->lock); 1213 head = &queue->head.list; 1214 pos = head->next; 1215 while(pos != head) { 1216 node = member_of(pos, mm_jpeg_q_node_t, list); 1217 data = (mm_jpeg_job_q_node_t *)node->data; 1218 1219 if (data && (data->entry.client_hdl == client_hdl)) { 1220 job_node = data; 1221 cam_list_del_node(&node->list); 1222 queue->size--; 1223 break; 1224 } 1225 pos = pos->next; 1226 } 1227 1228 pthread_mutex_unlock(&queue->lock); 1229 1230 return job_node; 1231 } 1232 1233 /* remove job from the queue with matching job id */ 1234 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_job_id(mm_jpeg_queue_t* queue, uint32_t job_id) 1235 { 1236 mm_jpeg_q_node_t* node = NULL; 1237 mm_jpeg_job_q_node_t* data = NULL; 1238 mm_jpeg_job_q_node_t* job_node = NULL; 1239 struct cam_list *head = NULL; 1240 struct cam_list *pos = NULL; 1241 1242 pthread_mutex_lock(&queue->lock); 1243 head = &queue->head.list; 1244 pos = head->next; 1245 while(pos != head) { 1246 node = member_of(pos, mm_jpeg_q_node_t, list); 1247 data = (mm_jpeg_job_q_node_t *)node->data; 1248 1249 if (data && (data->entry.jobId == job_id)) { 1250 job_node = data; 1251 cam_list_del_node(&node->list); 1252 queue->size--; 1253 break; 1254 } 1255 pos = pos->next; 1256 } 1257 1258 pthread_mutex_unlock(&queue->lock); 1259 1260 return job_node; 1261 } 1262 1263 /* update thumbnail dropped flag in job queue */ 1264 int32_t mm_jpeg_queue_update_flag(mm_jpeg_queue_t* queue, uint32_t job_id, uint8_t flag) 1265 { 1266 int32_t rc = 0; 1267 mm_jpeg_q_node_t* node = NULL; 1268 mm_jpeg_job_q_node_t* data = NULL; 1269 mm_jpeg_job_q_node_t* job_node = NULL; 1270 struct cam_list *head = NULL; 1271 struct cam_list *pos = NULL; 1272 1273 pthread_mutex_lock(&queue->lock); 1274 head = &queue->head.list; 1275 pos = head->next; 1276 while(pos != head) { 1277 node = member_of(pos, mm_jpeg_q_node_t, list); 1278 data = (mm_jpeg_job_q_node_t *)node->data; 1279 1280 if (data && (data->entry.jobId == job_id)) { 1281 job_node = data; 1282 break; 1283 } 1284 pos = pos->next; 1285 } 1286 1287 if (job_node) { 1288 /* find matching job for its job id */ 1289 job_node->entry.thumbnail_dropped = flag; 1290 } else { 1291 CDBG_ERROR("%s: No entry for jobId = %d", __func__, job_id); 1292 rc = -1; 1293 } 1294 pthread_mutex_unlock(&queue->lock); 1295 1296 return rc; 1297 } 1298