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