| /* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following |
| * disclaimer in the documentation and/or other materials provided |
| * with the distribution. |
| * * Neither the name of The Linux Foundation nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| */ |
| |
| // System dependencies |
| #include <pthread.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <math.h> |
| #define PRCTL_H <SYSTEM_HEADER_PREFIX/prctl.h> |
| #include PRCTL_H |
| |
| #ifdef LOAD_ADSP_RPC_LIB |
| #include <dlfcn.h> |
| #include <stdlib.h> |
| #endif |
| |
| // JPEG dependencies |
| #include "mm_jpeg_dbg.h" |
| #include "mm_jpeg_interface.h" |
| #include "mm_jpeg.h" |
| #include "mm_jpeg_inlines.h" |
| #ifdef LIB2D_ROTATION_ENABLE |
| #include "mm_lib2d.h" |
| #endif |
| |
| #define ENCODING_MODE_PARALLEL 1 |
| |
| #define META_KEYFILE QCAMERA_DUMP_FRM_LOCATION"metadata.key" |
| |
| /** |
| * minimal resolution needed for normal mode of ops |
| */ |
| #define MM_JPEG_MIN_NOM_RESOLUTION 7680000 /*8MP*/ |
| |
| #ifdef MM_JPEG_USE_PIPELINE |
| #undef MM_JPEG_CONCURRENT_SESSIONS_COUNT |
| #define MM_JPEG_CONCURRENT_SESSIONS_COUNT 1 |
| #endif |
| |
| OMX_ERRORTYPE mm_jpeg_ebd(OMX_HANDLETYPE hComponent, |
| OMX_PTR pAppData, |
| OMX_BUFFERHEADERTYPE* pBuffer); |
| OMX_ERRORTYPE mm_jpeg_fbd(OMX_HANDLETYPE hComponent, |
| OMX_PTR pAppData, |
| OMX_BUFFERHEADERTYPE* pBuffer); |
| OMX_ERRORTYPE mm_jpeg_event_handler(OMX_HANDLETYPE hComponent, |
| OMX_PTR pAppData, |
| OMX_EVENTTYPE eEvent, |
| OMX_U32 nData1, |
| OMX_U32 nData2, |
| OMX_PTR pEventData); |
| |
| static int32_t mm_jpegenc_destroy_job(mm_jpeg_job_session_t *p_session); |
| static void mm_jpegenc_job_done(mm_jpeg_job_session_t *p_session); |
| mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_dst_ptr( |
| mm_jpeg_queue_t* queue, void * dst_ptr); |
| static OMX_ERRORTYPE mm_jpeg_session_configure(mm_jpeg_job_session_t *p_session); |
| |
| /** mm_jpeg_get_comp_name: |
| * |
| * Arguments: |
| * None |
| * |
| * Return: |
| * Encoder component name |
| * |
| * Description: |
| * Get the name of omx component to be used for jpeg encoding |
| * |
| **/ |
| inline char* mm_jpeg_get_comp_name() |
| { |
| #ifdef MM_JPEG_USE_PIPELINE |
| return "OMX.qcom.image.jpeg.encoder_pipeline"; |
| #else |
| return "OMX.qcom.image.jpeg.encoder"; |
| #endif |
| } |
| |
| /** mm_jpeg_session_send_buffers: |
| * |
| * Arguments: |
| * @data: job session |
| * |
| * Return: |
| * OMX error values |
| * |
| * Description: |
| * Send the buffers to OMX layer |
| * |
| **/ |
| OMX_ERRORTYPE mm_jpeg_session_send_buffers(void *data) |
| { |
| uint32_t i = 0; |
| mm_jpeg_job_session_t* p_session = (mm_jpeg_job_session_t *)data; |
| OMX_ERRORTYPE ret = OMX_ErrorNone; |
| QOMX_BUFFER_INFO lbuffer_info; |
| mm_jpeg_encode_params_t *p_params = &p_session->params; |
| |
| memset(&lbuffer_info, 0x0, sizeof(QOMX_BUFFER_INFO)); |
| |
| if (p_session->lib2d_rotation_flag) { |
| for (i = 0; i < p_session->num_src_rot_bufs; i++) { |
| lbuffer_info.fd = (OMX_U32)p_session->src_rot_main_buf[i].fd; |
| LOGD("Source rot buffer %d", i); |
| ret = OMX_UseBuffer(p_session->omx_handle, |
| &(p_session->p_in_rot_omx_buf[i]), 0, |
| &lbuffer_info, p_session->src_rot_main_buf[i].buf_size, |
| p_session->src_rot_main_buf[i].buf_vaddr); |
| if (ret) { |
| LOGE("Error %d", ret); |
| return ret; |
| } |
| } |
| } else { |
| for (i = 0; i < p_params->num_src_bufs; i++) { |
| LOGD("Source buffer %d", i); |
| lbuffer_info.fd = (OMX_U32)p_params->src_main_buf[i].fd; |
| ret = OMX_UseBuffer(p_session->omx_handle, |
| &(p_session->p_in_omx_buf[i]), 0, |
| &lbuffer_info, p_params->src_main_buf[i].buf_size, |
| p_params->src_main_buf[i].buf_vaddr); |
| if (ret) { |
| LOGE("Error %d", ret); |
| return ret; |
| } |
| } |
| } |
| |
| if (p_session->lib2d_rotation_flag && p_session->thumb_from_main) { |
| for (i = 0; i < p_session->num_src_rot_bufs; i++) { |
| LOGD("Source rot buffer thumb %d", i); |
| lbuffer_info.fd = (OMX_U32)p_session->src_rot_main_buf[i].fd; |
| ret = OMX_UseBuffer(p_session->omx_handle, |
| &(p_session->p_in_rot_omx_thumb_buf[i]), 2, |
| &lbuffer_info, p_session->src_rot_main_buf[i].buf_size, |
| p_session->src_rot_main_buf[i].buf_vaddr); |
| if (ret) { |
| LOGE("Error %d", ret); |
| return ret; |
| } |
| } |
| } else { |
| for (i = 0; i < p_params->num_tmb_bufs; i++) { |
| LOGD("Source buffer %d", i); |
| lbuffer_info.fd = (OMX_U32)p_params->src_thumb_buf[i].fd; |
| ret = OMX_UseBuffer(p_session->omx_handle, |
| &(p_session->p_in_omx_thumb_buf[i]), 2, |
| &lbuffer_info, p_params->src_thumb_buf[i].buf_size, |
| p_params->src_thumb_buf[i].buf_vaddr); |
| if (ret) { |
| LOGE("Error %d", ret); |
| return ret; |
| } |
| } |
| } |
| |
| for (i = 0; i < p_params->num_dst_bufs; i++) { |
| LOGD("Dest buffer %d", i); |
| ret = OMX_UseBuffer(p_session->omx_handle, &(p_session->p_out_omx_buf[i]), |
| 1, NULL, p_params->dest_buf[i].buf_size, |
| p_params->dest_buf[i].buf_vaddr); |
| if (ret) { |
| LOGE("Error"); |
| return ret; |
| } |
| } |
| |
| return ret; |
| } |
| |
| |
| /** mm_jpeg_session_free_buffers: |
| * |
| * Arguments: |
| * @data: job session |
| * |
| * Return: |
| * OMX error values |
| * |
| * Description: |
| * Free the buffers from OMX layer |
| * |
| **/ |
| OMX_ERRORTYPE mm_jpeg_session_free_buffers(void *data) |
| { |
| OMX_ERRORTYPE ret = OMX_ErrorNone; |
| uint32_t i = 0; |
| mm_jpeg_job_session_t* p_session = (mm_jpeg_job_session_t *)data; |
| mm_jpeg_encode_params_t *p_params = &p_session->params; |
| |
| |
| if (p_session->lib2d_rotation_flag) { |
| for (i = 0; i < p_session->num_src_rot_bufs; i++) { |
| LOGD("Source rot buffer %d", i); |
| ret = OMX_FreeBuffer(p_session->omx_handle, 0, |
| p_session->p_in_rot_omx_buf[i]); |
| if (ret) { |
| LOGE("Error %d", ret); |
| return ret; |
| } |
| } |
| } else { |
| for (i = 0; i < p_params->num_src_bufs; i++) { |
| LOGD("Source buffer %d", i); |
| ret = OMX_FreeBuffer(p_session->omx_handle, 0, |
| p_session->p_in_omx_buf[i]); |
| if (ret) { |
| LOGE("Error %d", ret); |
| return ret; |
| } |
| } |
| } |
| |
| if (p_session->lib2d_rotation_flag && p_session->thumb_from_main) { |
| for (i = 0; i < p_session->num_src_rot_bufs; i++) { |
| LOGD("Source rot buffer thumb %d", i); |
| ret = OMX_FreeBuffer(p_session->omx_handle, 2, |
| p_session->p_in_rot_omx_thumb_buf[i]); |
| if (ret) { |
| LOGE("Error %d", ret); |
| return ret; |
| } |
| } |
| } else { |
| for (i = 0; i < p_params->num_tmb_bufs; i++) { |
| LOGD("Source buffer %d", i); |
| ret = OMX_FreeBuffer(p_session->omx_handle, 2, |
| p_session->p_in_omx_thumb_buf[i]); |
| if (ret) { |
| LOGE("Error %d", ret); |
| return ret; |
| } |
| } |
| } |
| |
| for (i = 0; i < p_params->num_dst_bufs; i++) { |
| LOGD("Dest buffer %d", i); |
| ret = OMX_FreeBuffer(p_session->omx_handle, 1, p_session->p_out_omx_buf[i]); |
| if (ret) { |
| LOGE("Error"); |
| return ret; |
| } |
| } |
| return ret; |
| } |
| |
| |
| |
| |
| /** mm_jpeg_session_change_state: |
| * |
| * Arguments: |
| * @p_session: job session |
| * @new_state: new state to be transitioned to |
| * @p_exec: transition function |
| * |
| * Return: |
| * OMX error values |
| * |
| * Description: |
| * This method is used for state transition |
| * |
| **/ |
| OMX_ERRORTYPE mm_jpeg_session_change_state(mm_jpeg_job_session_t* p_session, |
| OMX_STATETYPE new_state, |
| mm_jpeg_transition_func_t p_exec) |
| { |
| OMX_ERRORTYPE ret = OMX_ErrorNone; |
| OMX_STATETYPE current_state; |
| LOGD("new_state %d p_exec %p", |
| new_state, p_exec); |
| |
| |
| pthread_mutex_lock(&p_session->lock); |
| |
| ret = OMX_GetState(p_session->omx_handle, ¤t_state); |
| |
| if (ret) { |
| pthread_mutex_unlock(&p_session->lock); |
| return ret; |
| } |
| |
| if (current_state == new_state) { |
| pthread_mutex_unlock(&p_session->lock); |
| return OMX_ErrorNone; |
| } |
| |
| p_session->state_change_pending = OMX_TRUE; |
| pthread_mutex_unlock(&p_session->lock); |
| ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandStateSet, |
| new_state, NULL); |
| pthread_mutex_lock(&p_session->lock); |
| if (ret) { |
| LOGE("Error %d", ret); |
| pthread_mutex_unlock(&p_session->lock); |
| return OMX_ErrorIncorrectStateTransition; |
| } |
| if ((OMX_ErrorNone != p_session->error_flag) && |
| (OMX_ErrorOverflow != p_session->error_flag)) { |
| LOGE("Error %d", p_session->error_flag); |
| pthread_mutex_unlock(&p_session->lock); |
| return p_session->error_flag; |
| } |
| if (p_exec) { |
| ret = p_exec(p_session); |
| if (ret) { |
| LOGE("Error %d", ret); |
| pthread_mutex_unlock(&p_session->lock); |
| return ret; |
| } |
| } |
| if (p_session->state_change_pending) { |
| LOGL("before wait"); |
| pthread_cond_wait(&p_session->cond, &p_session->lock); |
| LOGL("after wait"); |
| } |
| pthread_mutex_unlock(&p_session->lock); |
| return ret; |
| } |
| |
| /** mm_jpeg_session_create: |
| * |
| * Arguments: |
| * @p_session: job session |
| * |
| * Return: |
| * OMX error types |
| * |
| * Description: |
| * Create a jpeg encode session |
| * |
| **/ |
| OMX_ERRORTYPE mm_jpeg_session_create(mm_jpeg_job_session_t* p_session) |
| { |
| OMX_ERRORTYPE rc = OMX_ErrorNone; |
| mm_jpeg_obj *my_obj = (mm_jpeg_obj *) p_session->jpeg_obj; |
| |
| pthread_mutex_init(&p_session->lock, NULL); |
| pthread_cond_init(&p_session->cond, NULL); |
| cirq_reset(&p_session->cb_q); |
| p_session->state_change_pending = OMX_FALSE; |
| p_session->abort_state = MM_JPEG_ABORT_NONE; |
| p_session->error_flag = OMX_ErrorNone; |
| p_session->ebd_count = 0; |
| p_session->fbd_count = 0; |
| p_session->encode_pid = -1; |
| p_session->config = OMX_FALSE; |
| p_session->exif_count_local = 0; |
| p_session->auto_out_buf = OMX_FALSE; |
| |
| p_session->omx_callbacks.EmptyBufferDone = mm_jpeg_ebd; |
| p_session->omx_callbacks.FillBufferDone = mm_jpeg_fbd; |
| p_session->omx_callbacks.EventHandler = mm_jpeg_event_handler; |
| |
| p_session->thumb_from_main = 0; |
| #ifdef MM_JPEG_USE_PIPELINE |
| p_session->thumb_from_main = !p_session->params.thumb_from_postview; |
| #endif |
| |
| rc = OMX_GetHandle(&p_session->omx_handle, |
| mm_jpeg_get_comp_name(), |
| (void *)p_session, |
| &p_session->omx_callbacks); |
| if (OMX_ErrorNone != rc) { |
| LOGE("OMX_GetHandle failed (%d)", rc); |
| return rc; |
| } |
| |
| my_obj->num_sessions++; |
| |
| return rc; |
| } |
| |
| |
| |
| /** mm_jpeg_session_destroy: |
| * |
| * Arguments: |
| * @p_session: job session |
| * |
| * Return: |
| * none |
| * |
| * Description: |
| * Destroy a jpeg encode session |
| * |
| **/ |
| void mm_jpeg_session_destroy(mm_jpeg_job_session_t* p_session) |
| { |
| OMX_ERRORTYPE rc = OMX_ErrorNone; |
| OMX_STATETYPE state; |
| uint32_t i; |
| mm_jpeg_obj *my_obj = (mm_jpeg_obj *) p_session->jpeg_obj; |
| |
| LOGD("E"); |
| if (NULL == p_session->omx_handle) { |
| LOGE("invalid handle"); |
| return; |
| } |
| |
| rc = OMX_GetState(p_session->omx_handle, &state); |
| |
| //Check state before state transition |
| if ((state == OMX_StateExecuting) || (state == OMX_StatePause)) { |
| rc = mm_jpeg_session_change_state(p_session, OMX_StateIdle, NULL); |
| if (rc) { |
| LOGE("Error"); |
| } |
| } |
| |
| rc = OMX_GetState(p_session->omx_handle, &state); |
| |
| if (state == OMX_StateIdle) { |
| rc = mm_jpeg_session_change_state(p_session, OMX_StateLoaded, |
| mm_jpeg_session_free_buffers); |
| if (rc) { |
| LOGE("Error"); |
| } |
| } |
| |
| if (p_session->lib2d_rotation_flag) { |
| for (i = 0; i < p_session->num_src_rot_bufs; i++) { |
| if (p_session->src_rot_ion_buffer[i].addr) { |
| buffer_deallocate(&p_session->src_rot_ion_buffer[i]); |
| } |
| } |
| } |
| |
| /* If current session is the session in progress |
| set session in progress pointer to null*/ |
| p_session->config = OMX_FALSE; |
| if (my_obj->p_session_inprogress == p_session) { |
| my_obj->p_session_inprogress = NULL; |
| } |
| |
| rc = OMX_FreeHandle(p_session->omx_handle); |
| if (0 != rc) { |
| LOGE("OMX_FreeHandle failed (%d)", rc); |
| } |
| p_session->omx_handle = NULL; |
| |
| pthread_mutex_destroy(&p_session->lock); |
| pthread_cond_destroy(&p_session->cond); |
| |
| if (NULL != p_session->meta_enc_key) { |
| free(p_session->meta_enc_key); |
| p_session->meta_enc_key = NULL; |
| } |
| |
| my_obj->num_sessions--; |
| |
| // Destroy next session |
| if (p_session->next_session) { |
| mm_jpeg_session_destroy(p_session->next_session); |
| } |
| |
| LOGD("Session destroy successful. X"); |
| } |
| |
| |
| |
| /** mm_jpeg_session_config_main_buffer_offset: |
| * |
| * Arguments: |
| * @p_session: job session |
| * |
| * Return: |
| * OMX error values |
| * |
| * Description: |
| * Configure the buffer offsets |
| * |
| **/ |
| OMX_ERRORTYPE mm_jpeg_session_config_main_buffer_offset( |
| mm_jpeg_job_session_t* p_session) |
| { |
| OMX_ERRORTYPE rc = 0; |
| OMX_INDEXTYPE buffer_index; |
| QOMX_YUV_FRAME_INFO frame_info; |
| size_t totalSize = 0; |
| mm_jpeg_encode_params_t *p_params = &p_session->params; |
| |
| mm_jpeg_buf_t *p_src_buf = |
| &p_params->src_main_buf[0]; |
| |
| memset(&frame_info, 0x0, sizeof(QOMX_YUV_FRAME_INFO)); |
| |
| frame_info.cbcrStartOffset[0] = p_src_buf->offset.mp[0].len; |
| frame_info.cbcrStartOffset[1] = p_src_buf->offset.mp[1].len; |
| if (!p_session->lib2d_rotation_flag) { |
| frame_info.yOffset = p_src_buf->offset.mp[0].offset; |
| frame_info.cbcrOffset[0] = p_src_buf->offset.mp[1].offset; |
| frame_info.cbcrOffset[1] = p_src_buf->offset.mp[2].offset; |
| } |
| totalSize = p_src_buf->buf_size; |
| |
| rc = OMX_GetExtensionIndex(p_session->omx_handle, |
| QOMX_IMAGE_EXT_BUFFER_OFFSET_NAME, &buffer_index); |
| if (rc != OMX_ErrorNone) { |
| LOGE("Failed"); |
| return rc; |
| } |
| |
| LOGD("yOffset = %d, cbcrOffset = (%d %d), totalSize = %zd," |
| "cbcrStartOffset = (%d %d)", |
| (int)frame_info.yOffset, |
| (int)frame_info.cbcrOffset[0], |
| (int)frame_info.cbcrOffset[1], |
| totalSize, |
| (int)frame_info.cbcrStartOffset[0], |
| (int)frame_info.cbcrStartOffset[1]); |
| |
| rc = OMX_SetParameter(p_session->omx_handle, buffer_index, &frame_info); |
| if (rc != OMX_ErrorNone) { |
| LOGE("Failed"); |
| return rc; |
| } |
| return rc; |
| } |
| |
| /** mm_jpeg_encoding_mode: |
| * |
| * Arguments: |
| * @p_session: job session |
| * |
| * Return: |
| * OMX error values |
| * |
| * Description: |
| * Configure the serial or parallel encoding |
| * mode |
| * |
| **/ |
| OMX_ERRORTYPE mm_jpeg_encoding_mode( |
| mm_jpeg_job_session_t* p_session) |
| { |
| OMX_ERRORTYPE rc = 0; |
| OMX_INDEXTYPE indextype; |
| QOMX_ENCODING_MODE encoding_mode; |
| |
| rc = OMX_GetExtensionIndex(p_session->omx_handle, |
| QOMX_IMAGE_EXT_ENCODING_MODE_NAME, &indextype); |
| if (rc != OMX_ErrorNone) { |
| LOGE("Failed"); |
| return rc; |
| } |
| |
| if (ENCODING_MODE_PARALLEL) { |
| encoding_mode = OMX_Parallel_Encoding; |
| } else { |
| encoding_mode = OMX_Serial_Encoding; |
| } |
| LOGD("encoding mode = %d ", |
| (int)encoding_mode); |
| rc = OMX_SetParameter(p_session->omx_handle, indextype, &encoding_mode); |
| if (rc != OMX_ErrorNone) { |
| LOGE("Failed"); |
| return rc; |
| } |
| return rc; |
| } |
| |
| /** mm_jpeg_get_speed: |
| * |
| * Arguments: |
| * @p_session: job session |
| * |
| * Return: |
| * ops speed type for jpeg |
| * |
| * Description: |
| * Configure normal or high speed jpeg |
| * |
| **/ |
| QOMX_JPEG_SPEED_MODE mm_jpeg_get_speed( |
| mm_jpeg_job_session_t* p_session) |
| { |
| mm_jpeg_encode_params_t *p_params = &p_session->params; |
| cam_dimension_t *p_dim = &p_params->main_dim.src_dim; |
| if (p_params->burst_mode || |
| (MM_JPEG_MIN_NOM_RESOLUTION < (p_dim->width * p_dim->height))) { |
| return QOMX_JPEG_SPEED_MODE_HIGH; |
| } |
| return QOMX_JPEG_SPEED_MODE_NORMAL; |
| } |
| |
| /** mm_jpeg_speed_mode: |
| * |
| * Arguments: |
| * @p_session: job session |
| * |
| * Return: |
| * OMX error values |
| * |
| * Description: |
| * Configure normal or high speed jpeg |
| * |
| **/ |
| OMX_ERRORTYPE mm_jpeg_speed_mode( |
| mm_jpeg_job_session_t* p_session) |
| { |
| OMX_ERRORTYPE rc = 0; |
| OMX_INDEXTYPE indextype; |
| QOMX_JPEG_SPEED jpeg_speed; |
| |
| rc = OMX_GetExtensionIndex(p_session->omx_handle, |
| QOMX_IMAGE_EXT_JPEG_SPEED_NAME, &indextype); |
| if (rc != OMX_ErrorNone) { |
| LOGE("Failed"); |
| return rc; |
| } |
| |
| jpeg_speed.speedMode = mm_jpeg_get_speed(p_session); |
| LOGH("speed %d", jpeg_speed.speedMode); |
| |
| rc = OMX_SetParameter(p_session->omx_handle, indextype, &jpeg_speed); |
| if (rc != OMX_ErrorNone) { |
| LOGE("Failed"); |
| return rc; |
| } |
| return rc; |
| } |
| |
| /** mm_jpeg_get_mem: |
| * |
| * Arguments: |
| * @p_out_buf : jpeg output buffer |
| * @p_jpeg_session: job session |
| * |
| * Return: |
| * 0 for success else failure |
| * |
| * Description: |
| * gets the jpeg output buffer |
| * |
| **/ |
| static int32_t mm_jpeg_get_mem( |
| omx_jpeg_ouput_buf_t *p_out_buf, void* p_jpeg_session) |
| { |
| int32_t rc = 0; |
| mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *)p_jpeg_session; |
| mm_jpeg_encode_params_t *p_params = NULL; |
| mm_jpeg_encode_job_t *p_encode_job = NULL; |
| |
| if (!p_session) { |
| LOGE("Invalid input"); |
| return -1; |
| } |
| p_params = &p_session->params; |
| p_encode_job = &p_session->encode_job; |
| if (!p_params || !p_encode_job || !p_params->get_memory) { |
| LOGE("Invalid jpeg encode params"); |
| return -1; |
| } |
| p_params->get_memory(p_out_buf); |
| p_encode_job->ref_count++; |
| p_encode_job->alloc_out_buffer = p_out_buf; |
| LOGD("ref_count %d p_out_buf %p", |
| p_encode_job->ref_count, p_out_buf); |
| return rc; |
| } |
| |
| /** mm_jpeg_put_mem: |
| * |
| * Arguments: |
| * @p_jpeg_session: job session |
| * |
| * Return: |
| * 0 for success else failure |
| * |
| * Description: |
| * releases the jpeg output buffer |
| * |
| **/ |
| static int32_t mm_jpeg_put_mem(void* p_jpeg_session) |
| { |
| int32_t rc = 0; |
| mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *)p_jpeg_session; |
| mm_jpeg_encode_params_t *p_params = NULL; |
| mm_jpeg_encode_job_t *p_encode_job = NULL; |
| |
| if (!p_session) { |
| LOGE("Invalid input"); |
| return -1; |
| } |
| p_params = &p_session->params; |
| p_encode_job = &p_session->encode_job; |
| |
| if (!p_params->get_memory) { |
| LOGD("get_mem not defined, ignore put mem"); |
| return 0; |
| } |
| if (!p_params || !p_encode_job || !p_params->put_memory) { |
| LOGE("Invalid jpeg encode params"); |
| return -1; |
| } |
| if ((MM_JPEG_ABORT_NONE != p_session->abort_state) && |
| p_encode_job->ref_count) { |
| omx_jpeg_ouput_buf_t *p_out_buf = |
| ( omx_jpeg_ouput_buf_t *) p_encode_job->alloc_out_buffer; |
| p_params->put_memory(p_out_buf); |
| p_encode_job->ref_count--; |
| p_encode_job->alloc_out_buffer = NULL; |
| } else if (p_encode_job->ref_count) { |
| p_encode_job->ref_count--; |
| } else { |
| LOGW("Buffer already released %d", p_encode_job->ref_count); |
| rc = -1; |
| } |
| LOGD("ref_count %d p_out_buf %p", |
| p_encode_job->ref_count, p_encode_job->alloc_out_buffer); |
| return rc; |
| } |
| |
| /** mm_jpeg_mem_ops: |
| * |
| * Arguments: |
| * @p_session: job session |
| * |
| * Return: |
| * OMX error values |
| * |
| * Description: |
| * Configure the serial or parallel encoding |
| * mode |
| * |
| **/ |
| OMX_ERRORTYPE mm_jpeg_mem_ops( |
| mm_jpeg_job_session_t* p_session) |
| { |
| OMX_ERRORTYPE rc = 0; |
| OMX_INDEXTYPE indextype; |
| QOMX_MEM_OPS mem_ops; |
| mm_jpeg_encode_params_t *p_params = &p_session->params; |
| |
| if (p_params->get_memory) { |
| mem_ops.get_memory = mm_jpeg_get_mem; |
| } else { |
| mem_ops.get_memory = NULL; |
| LOGH("HAL get_mem handler undefined"); |
| } |
| |
| mem_ops.psession = p_session; |
| rc = OMX_GetExtensionIndex(p_session->omx_handle, |
| QOMX_IMAGE_EXT_MEM_OPS_NAME, &indextype); |
| if (rc != OMX_ErrorNone) { |
| LOGE("Failed"); |
| return rc; |
| } |
| |
| rc = OMX_SetParameter(p_session->omx_handle, indextype, &mem_ops); |
| if (rc != OMX_ErrorNone) { |
| LOGE("Failed"); |
| return rc; |
| } |
| return rc; |
| } |
| |
| /** mm_jpeg_metadata: |
| * |
| * Arguments: |
| * @p_session: job session |
| * |
| * Return: |
| * OMX error values |
| * |
| * Description: |
| * Pass meta data |
| * |
| **/ |
| OMX_ERRORTYPE mm_jpeg_metadata( |
| mm_jpeg_job_session_t* p_session) |
| { |
| OMX_ERRORTYPE rc = OMX_ErrorNone; |
| OMX_INDEXTYPE indexType; |
| QOMX_METADATA lMeta; |
| mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; |
| mm_jpeg_obj *my_obj = (mm_jpeg_obj *) p_session->jpeg_obj; |
| |
| rc = OMX_GetExtensionIndex(p_session->omx_handle, |
| QOMX_IMAGE_EXT_METADATA_NAME, &indexType); |
| |
| if (rc != OMX_ErrorNone) { |
| LOGE("Failed"); |
| return rc; |
| } |
| |
| lMeta.metadata = (OMX_U8 *)p_jobparams->p_metadata; |
| lMeta.metaPayloadSize = sizeof(*p_jobparams->p_metadata); |
| lMeta.mobicat_mask = p_jobparams->mobicat_mask; |
| lMeta.static_metadata = (OMX_U8 *)my_obj->jpeg_metadata; |
| |
| rc = OMX_SetConfig(p_session->omx_handle, indexType, &lMeta); |
| if (rc != OMX_ErrorNone) { |
| LOGE("Failed"); |
| return rc; |
| } |
| return OMX_ErrorNone; |
| } |
| |
| /** mm_jpeg_meta_enc_key: |
| * |
| * Arguments: |
| * @p_session: job session |
| * |
| * Return: |
| * OMX error values |
| * |
| * Description: |
| * Pass metadata encrypt key |
| * |
| **/ |
| OMX_ERRORTYPE mm_jpeg_meta_enc_key( |
| mm_jpeg_job_session_t* p_session) |
| { |
| OMX_ERRORTYPE rc = OMX_ErrorNone; |
| OMX_INDEXTYPE indexType; |
| QOMX_META_ENC_KEY lKey; |
| |
| lKey.metaKey = p_session->meta_enc_key; |
| lKey.keyLen = p_session->meta_enc_keylen; |
| |
| if ((!lKey.metaKey) || (!lKey.keyLen)){ |
| LOGD("Key is invalid"); |
| return OMX_ErrorNone; |
| } |
| |
| rc = OMX_GetExtensionIndex(p_session->omx_handle, |
| QOMX_IMAGE_EXT_META_ENC_KEY_NAME, &indexType); |
| |
| if (rc != OMX_ErrorNone) { |
| LOGE("Failed"); |
| return rc; |
| } |
| |
| rc = OMX_SetConfig(p_session->omx_handle, indexType, &lKey); |
| if (rc != OMX_ErrorNone) { |
| LOGE("Failed"); |
| return rc; |
| } |
| return OMX_ErrorNone; |
| } |
| |
| /** map_jpeg_format: |
| * |
| * Arguments: |
| * @color_fmt: color format |
| * |
| * Return: |
| * OMX color format |
| * |
| * Description: |
| * Map mmjpeg color format to OMX color format |
| * |
| **/ |
| int map_jpeg_format(mm_jpeg_color_format color_fmt) |
| { |
| switch (color_fmt) { |
| case MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2: |
| return (int)OMX_QCOM_IMG_COLOR_FormatYVU420SemiPlanar; |
| case MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2: |
| return (int)OMX_COLOR_FormatYUV420SemiPlanar; |
| case MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V1: |
| return (int)OMX_QCOM_IMG_COLOR_FormatYVU422SemiPlanar; |
| case MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V1: |
| return (int)OMX_COLOR_FormatYUV422SemiPlanar; |
| case MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V2: |
| return (int)OMX_QCOM_IMG_COLOR_FormatYVU422SemiPlanar_h1v2; |
| case MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V2: |
| return (int)OMX_QCOM_IMG_COLOR_FormatYUV422SemiPlanar_h1v2; |
| case MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V1: |
| return (int)OMX_QCOM_IMG_COLOR_FormatYVU444SemiPlanar; |
| case MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V1: |
| return (int)OMX_QCOM_IMG_COLOR_FormatYUV444SemiPlanar; |
| case MM_JPEG_COLOR_FORMAT_MONOCHROME: |
| return (int)OMX_COLOR_FormatMonochrome; |
| default: |
| LOGW("invalid format %d", color_fmt); |
| return (int)OMX_QCOM_IMG_COLOR_FormatYVU420SemiPlanar; |
| } |
| } |
| |
| /** mm_jpeg_get_imgfmt_from_colorfmt: |
| * |
| * Arguments: |
| * @color_fmt: color format |
| * |
| * Return: |
| * cam format |
| * |
| * Description: |
| * Get camera image format from color format |
| * |
| **/ |
| cam_format_t mm_jpeg_get_imgfmt_from_colorfmt |
| (mm_jpeg_color_format color_fmt) |
| { |
| switch (color_fmt) { |
| case MM_JPEG_COLOR_FORMAT_MONOCHROME: |
| return CAM_FORMAT_Y_ONLY; |
| case MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2: |
| return CAM_FORMAT_YUV_420_NV21; |
| case MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2: |
| return CAM_FORMAT_YUV_420_NV12; |
| case MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V1: |
| case MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V2: |
| return CAM_FORMAT_YUV_422_NV61; |
| case MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V1: |
| case MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V2: |
| return CAM_FORMAT_YUV_422_NV16; |
| case MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V1: |
| return CAM_FORMAT_YUV_444_NV42; |
| case MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V1: |
| return CAM_FORMAT_YUV_444_NV24; |
| default: |
| return CAM_FORMAT_Y_ONLY; |
| } |
| } |
| |
| /** mm_jpeg_session_config_port: |
| * |
| * Arguments: |
| * @p_session: job session |
| * |
| * Return: |
| * OMX error values |
| * |
| * Description: |
| * Configure OMX ports |
| * |
| **/ |
| OMX_ERRORTYPE mm_jpeg_session_config_ports(mm_jpeg_job_session_t* p_session) |
| { |
| OMX_ERRORTYPE ret = OMX_ErrorNone; |
| mm_jpeg_encode_params_t *p_params = &p_session->params; |
| OMX_CONFIG_ROTATIONTYPE rotate; |
| |
| mm_jpeg_buf_t *p_src_buf = |
| &p_params->src_main_buf[0]; |
| |
| p_session->inputPort.nPortIndex = 0; |
| p_session->outputPort.nPortIndex = 1; |
| p_session->inputTmbPort.nPortIndex = 2; |
| |
| ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, |
| &p_session->inputPort); |
| if (ret) { |
| LOGE("failed"); |
| return ret; |
| } |
| |
| ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, |
| &p_session->inputTmbPort); |
| if (ret) { |
| LOGE("failed"); |
| return ret; |
| } |
| |
| ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, |
| &p_session->outputPort); |
| if (ret) { |
| LOGE("failed"); |
| return ret; |
| } |
| |
| if (p_session->lib2d_rotation_flag && |
| ((p_session->params.rotation == 90) || |
| (p_session->params.rotation == 270))) { |
| p_session->inputPort.format.image.nFrameWidth = |
| (OMX_U32)p_params->main_dim.src_dim.height; |
| p_session->inputPort.format.image.nFrameHeight = |
| (OMX_U32)p_params->main_dim.src_dim.width; |
| p_session->inputPort.format.image.nStride = |
| p_src_buf->offset.mp[0].scanline; |
| p_session->inputPort.format.image.nSliceHeight = |
| (OMX_U32)p_src_buf->offset.mp[0].stride; |
| } else { |
| p_session->inputPort.format.image.nFrameWidth = |
| (OMX_U32)p_params->main_dim.src_dim.width; |
| p_session->inputPort.format.image.nFrameHeight = |
| (OMX_U32)p_params->main_dim.src_dim.height; |
| p_session->inputPort.format.image.nStride = |
| p_src_buf->offset.mp[0].stride; |
| p_session->inputPort.format.image.nSliceHeight = |
| (OMX_U32)p_src_buf->offset.mp[0].scanline; |
| } |
| |
| p_session->inputPort.format.image.eColorFormat = |
| map_jpeg_format(p_params->color_format); |
| p_session->inputPort.nBufferSize = |
| p_params->src_main_buf[0/*p_jobparams->src_index*/].buf_size; |
| |
| if (p_session->lib2d_rotation_flag) { |
| p_session->inputPort.nBufferCountActual = |
| (OMX_U32)p_session->num_src_rot_bufs; |
| } else { |
| p_session->inputPort.nBufferCountActual = |
| (OMX_U32)p_params->num_src_bufs; |
| } |
| |
| ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, |
| &p_session->inputPort); |
| if (ret) { |
| LOGE("failed"); |
| return ret; |
| } |
| |
| if (p_session->params.encode_thumbnail) { |
| mm_jpeg_buf_t *p_tmb_buf = |
| &p_params->src_thumb_buf[0]; |
| if ((p_session->lib2d_rotation_flag && p_session->thumb_from_main) && |
| ((p_session->params.rotation == 90) || |
| (p_session->params.rotation == 270))) { |
| p_session->inputTmbPort.format.image.nFrameWidth = |
| (OMX_U32)p_params->thumb_dim.src_dim.height; |
| p_session->inputTmbPort.format.image.nFrameHeight = |
| (OMX_U32)p_params->thumb_dim.src_dim.width; |
| p_session->inputTmbPort.format.image.nStride = |
| p_tmb_buf->offset.mp[0].scanline; |
| p_session->inputTmbPort.format.image.nSliceHeight = |
| (OMX_U32)p_tmb_buf->offset.mp[0].stride; |
| } else { |
| p_session->inputTmbPort.format.image.nFrameWidth = |
| (OMX_U32)p_params->thumb_dim.src_dim.width; |
| p_session->inputTmbPort.format.image.nFrameHeight = |
| (OMX_U32)p_params->thumb_dim.src_dim.height; |
| p_session->inputTmbPort.format.image.nStride = |
| p_tmb_buf->offset.mp[0].stride; |
| p_session->inputTmbPort.format.image.nSliceHeight = |
| (OMX_U32)p_tmb_buf->offset.mp[0].scanline; |
| } |
| |
| p_session->inputTmbPort.format.image.eColorFormat = |
| map_jpeg_format(p_params->thumb_color_format); |
| p_session->inputTmbPort.nBufferSize = |
| p_params->src_thumb_buf[0].buf_size; |
| |
| if (p_session->lib2d_rotation_flag && p_session->thumb_from_main) { |
| p_session->inputTmbPort.nBufferCountActual = |
| (OMX_U32)p_session->num_src_rot_bufs; |
| } else { |
| p_session->inputTmbPort.nBufferCountActual = |
| (OMX_U32)p_params->num_tmb_bufs; |
| } |
| |
| ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, |
| &p_session->inputTmbPort); |
| |
| if (ret) { |
| LOGE("failed"); |
| return ret; |
| } |
| |
| // Enable thumbnail port |
| ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortEnable, |
| p_session->inputTmbPort.nPortIndex, NULL); |
| |
| if (ret) { |
| LOGE("failed"); |
| return ret; |
| } |
| } else { |
| // Disable thumbnail port |
| ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortDisable, |
| p_session->inputTmbPort.nPortIndex, NULL); |
| |
| if (ret) { |
| LOGE("failed"); |
| return ret; |
| } |
| } |
| |
| p_session->outputPort.nBufferSize = |
| p_params->dest_buf[0].buf_size; |
| p_session->outputPort.nBufferCountActual = (OMX_U32)p_params->num_dst_bufs; |
| ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition, |
| &p_session->outputPort); |
| if (ret) { |
| LOGE("failed"); |
| return ret; |
| } |
| |
| /* set rotation */ |
| memset(&rotate, 0, sizeof(rotate)); |
| rotate.nPortIndex = 1; |
| |
| if (p_session->lib2d_rotation_flag) { |
| rotate.nRotation = 0; |
| } else { |
| rotate.nRotation = (OMX_S32)p_params->rotation; |
| } |
| |
| ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonRotate, |
| &rotate); |
| if (OMX_ErrorNone != ret) { |
| LOGE("Error %d", ret); |
| return ret; |
| } |
| LOGD("Set rotation to %d at port_idx = %d", |
| (int)p_params->rotation, (int)rotate.nPortIndex); |
| |
| return ret; |
| } |
| |
| /** mm_jpeg_update_thumbnail_crop |
| * |
| * Arguments: |
| * @p_thumb_dim: thumbnail dimension |
| * @crop_width : flag indicating if width needs to be cropped |
| * |
| * Return: |
| * OMX error values |
| * |
| * Description: |
| * Updates thumbnail crop aspect ratio based on |
| * thumbnail destination aspect ratio. |
| * |
| */ |
| OMX_ERRORTYPE mm_jpeg_update_thumbnail_crop(mm_jpeg_dim_t *p_thumb_dim, |
| uint8_t crop_width) |
| { |
| OMX_ERRORTYPE ret = OMX_ErrorNone; |
| int32_t cropped_width = 0, cropped_height = 0; |
| |
| if (crop_width) { |
| // Keep height constant |
| cropped_height = p_thumb_dim->crop.height; |
| cropped_width = floor((cropped_height * p_thumb_dim->dst_dim.width) / |
| p_thumb_dim->dst_dim.height); |
| if (cropped_width % 2) { |
| cropped_width -= 1; |
| } |
| } else { |
| // Keep width constant |
| cropped_width = p_thumb_dim->crop.width; |
| cropped_height = floor((cropped_width * p_thumb_dim->dst_dim.height) / |
| p_thumb_dim->dst_dim.width); |
| if (cropped_height % 2) { |
| cropped_height -= 1; |
| } |
| } |
| p_thumb_dim->crop.left = p_thumb_dim->crop.left + |
| floor((p_thumb_dim->crop.width - cropped_width) / 2); |
| if (p_thumb_dim->crop.left % 2) { |
| p_thumb_dim->crop.left -= 1; |
| } |
| p_thumb_dim->crop.top = p_thumb_dim->crop.top + |
| floor((p_thumb_dim->crop.height - cropped_height) / 2); |
| if (p_thumb_dim->crop.top % 2) { |
| p_thumb_dim->crop.top -= 1; |
| } |
| p_thumb_dim->crop.width = cropped_width; |
| p_thumb_dim->crop.height = cropped_height; |
| |
| LOGH("New thumbnail crop: left %d, top %d, crop width %d," |
| " crop height %d", p_thumb_dim->crop.left, |
| p_thumb_dim->crop.top, p_thumb_dim->crop.width, |
| p_thumb_dim->crop.height); |
| |
| return ret; |
| } |
| |
| /** mm_jpeg_omx_config_thumbnail: |
| * |
| * Arguments: |
| * @p_session: job session |
| * |
| * Return: |
| * OMX error values |
| * |
| * Description: |
| * Configure OMX ports |
| * |
| **/ |
| OMX_ERRORTYPE mm_jpeg_session_config_thumbnail(mm_jpeg_job_session_t* p_session) |
| { |
| OMX_ERRORTYPE ret = OMX_ErrorNone; |
| QOMX_THUMBNAIL_INFO thumbnail_info; |
| OMX_INDEXTYPE thumb_indextype; |
| mm_jpeg_encode_params_t *p_params = &p_session->params; |
| mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; |
| mm_jpeg_dim_t *p_thumb_dim = &p_jobparams->thumb_dim; |
| mm_jpeg_dim_t *p_main_dim = &p_jobparams->main_dim; |
| QOMX_YUV_FRAME_INFO *p_frame_info = &thumbnail_info.tmbOffset; |
| mm_jpeg_buf_t *p_tmb_buf = &p_params->src_thumb_buf[p_jobparams->thumb_index]; |
| |
| LOGH("encode_thumbnail %u", |
| p_params->encode_thumbnail); |
| if (OMX_FALSE == p_params->encode_thumbnail) { |
| return ret; |
| } |
| |
| if ((p_thumb_dim->dst_dim.width == 0) || (p_thumb_dim->dst_dim.height == 0)) { |
| LOGE("Error invalid output dim for thumbnail"); |
| return OMX_ErrorBadParameter; |
| } |
| |
| if ((p_thumb_dim->src_dim.width == 0) || (p_thumb_dim->src_dim.height == 0)) { |
| LOGE("Error invalid input dim for thumbnail"); |
| return OMX_ErrorBadParameter; |
| } |
| |
| if ((p_thumb_dim->crop.width == 0) || (p_thumb_dim->crop.height == 0)) { |
| p_thumb_dim->crop.width = p_thumb_dim->src_dim.width; |
| p_thumb_dim->crop.height = p_thumb_dim->src_dim.height; |
| } |
| |
| /* check crop boundary */ |
| if ((p_thumb_dim->crop.width + p_thumb_dim->crop.left > p_thumb_dim->src_dim.width) || |
| (p_thumb_dim->crop.height + p_thumb_dim->crop.top > p_thumb_dim->src_dim.height)) { |
| LOGE("invalid crop boundary (%d, %d) offset (%d, %d) out of (%d, %d)", |
| p_thumb_dim->crop.width, |
| p_thumb_dim->crop.height, |
| p_thumb_dim->crop.left, |
| p_thumb_dim->crop.top, |
| p_thumb_dim->src_dim.width, |
| p_thumb_dim->src_dim.height); |
| return OMX_ErrorBadParameter; |
| } |
| |
| memset(&thumbnail_info, 0x0, sizeof(QOMX_THUMBNAIL_INFO)); |
| ret = OMX_GetExtensionIndex(p_session->omx_handle, |
| QOMX_IMAGE_EXT_THUMBNAIL_NAME, |
| &thumb_indextype); |
| if (ret) { |
| LOGE("Error %d", ret); |
| return ret; |
| } |
| |
| /* fill thumbnail info */ |
| thumbnail_info.scaling_enabled = 1; |
| thumbnail_info.input_width = (OMX_U32)p_thumb_dim->src_dim.width; |
| thumbnail_info.input_height = (OMX_U32)p_thumb_dim->src_dim.height; |
| thumbnail_info.rotation = (OMX_U32)p_params->thumb_rotation; |
| thumbnail_info.quality = (OMX_U32)p_params->thumb_quality; |
| thumbnail_info.output_width = (OMX_U32)p_thumb_dim->dst_dim.width; |
| thumbnail_info.output_height = (OMX_U32)p_thumb_dim->dst_dim.height; |
| |
| if (p_session->thumb_from_main) { |
| |
| if (p_session->lib2d_rotation_flag) { |
| thumbnail_info.rotation = 0; |
| } else { |
| if ((p_session->params.thumb_rotation == 90 || |
| p_session->params.thumb_rotation == 270) && |
| (p_session->params.rotation == 0 || |
| p_session->params.rotation == 180)) { |
| |
| thumbnail_info.output_width = (OMX_U32)p_thumb_dim->dst_dim.height; |
| thumbnail_info.output_height = (OMX_U32)p_thumb_dim->dst_dim.width; |
| thumbnail_info.rotation = p_session->params.rotation; |
| } |
| } |
| |
| //Thumb FOV should be within main image FOV |
| if (p_thumb_dim->crop.left < p_main_dim->crop.left) { |
| p_thumb_dim->crop.left = p_main_dim->crop.left; |
| } |
| |
| if (p_thumb_dim->crop.top < p_main_dim->crop.top) { |
| p_thumb_dim->crop.top = p_main_dim->crop.top; |
| } |
| |
| while ((p_thumb_dim->crop.left + p_thumb_dim->crop.width) > |
| (p_main_dim->crop.left + p_main_dim->crop.width)) { |
| if (p_thumb_dim->crop.left == p_main_dim->crop.left) { |
| p_thumb_dim->crop.width = p_main_dim->crop.width; |
| } else { |
| p_thumb_dim->crop.left = p_main_dim->crop.left; |
| } |
| } |
| |
| while ((p_thumb_dim->crop.top + p_thumb_dim->crop.height) > |
| (p_main_dim->crop.top + p_main_dim->crop.height)) { |
| if (p_thumb_dim->crop.top == p_main_dim->crop.top) { |
| p_thumb_dim->crop.height = p_main_dim->crop.height; |
| } else { |
| p_thumb_dim->crop.top = p_main_dim->crop.top; |
| } |
| } |
| } else if ((p_thumb_dim->dst_dim.width > p_thumb_dim->src_dim.width) || |
| (p_thumb_dim->dst_dim.height > p_thumb_dim->src_dim.height)) { |
| LOGE("Incorrect thumbnail dim %dx%d resetting to %dx%d", p_thumb_dim->dst_dim.width, |
| p_thumb_dim->dst_dim.height, p_thumb_dim->src_dim.width, |
| p_thumb_dim->src_dim.height); |
| thumbnail_info.output_width = (OMX_U32)p_thumb_dim->src_dim.width; |
| thumbnail_info.output_height = (OMX_U32)p_thumb_dim->src_dim.height; |
| } |
| |
| // If the thumbnail crop aspect ratio image and thumbnail dest aspect |
| // ratio are different, reset the thumbnail crop |
| double thumbcrop_aspect_ratio = (double)p_thumb_dim->crop.width / |
| (double)p_thumb_dim->crop.height; |
| double thumbdst_aspect_ratio = (double)p_thumb_dim->dst_dim.width / |
| (double)p_thumb_dim->dst_dim.height; |
| if ((thumbdst_aspect_ratio - thumbcrop_aspect_ratio) > |
| ASPECT_TOLERANCE) { |
| mm_jpeg_update_thumbnail_crop(p_thumb_dim, 0); |
| } else if ((thumbcrop_aspect_ratio - thumbdst_aspect_ratio) > |
| ASPECT_TOLERANCE) { |
| mm_jpeg_update_thumbnail_crop(p_thumb_dim, 1); |
| } |
| |
| // Fill thumbnail crop info |
| thumbnail_info.crop_info.nWidth = (OMX_U32)p_thumb_dim->crop.width; |
| thumbnail_info.crop_info.nHeight = (OMX_U32)p_thumb_dim->crop.height; |
| thumbnail_info.crop_info.nLeft = p_thumb_dim->crop.left; |
| thumbnail_info.crop_info.nTop = p_thumb_dim->crop.top; |
| |
| memset(p_frame_info, 0x0, sizeof(*p_frame_info)); |
| |
| p_frame_info->cbcrStartOffset[0] = p_tmb_buf->offset.mp[0].len; |
| p_frame_info->cbcrStartOffset[1] = p_tmb_buf->offset.mp[1].len; |
| p_frame_info->yOffset = p_tmb_buf->offset.mp[0].offset; |
| p_frame_info->cbcrOffset[0] = p_tmb_buf->offset.mp[1].offset; |
| p_frame_info->cbcrOffset[1] = p_tmb_buf->offset.mp[2].offset; |
| |
| if (p_session->lib2d_rotation_flag && p_session->thumb_from_main) { |
| p_frame_info->yOffset = 0; |
| p_frame_info->cbcrOffset[0] = 0; |
| p_frame_info->cbcrOffset[1] = 0; |
| } |
| |
| ret = OMX_SetConfig(p_session->omx_handle, thumb_indextype, |
| &thumbnail_info); |
| if (ret) { |
| LOGE("Error"); |
| return ret; |
| } |
| |
| return ret; |
| } |
| |
| /** mm_jpeg_session_config_main_crop: |
| * |
| * Arguments: |
| * @p_session: job session |
| * |
| * Return: |
| * OMX error values |
| * |
| * Description: |
| * Configure main image crop |
| * |
| **/ |
| OMX_ERRORTYPE mm_jpeg_session_config_main_crop(mm_jpeg_job_session_t *p_session) |
| { |
| OMX_CONFIG_RECTTYPE rect_type_in, rect_type_out; |
| OMX_ERRORTYPE ret = OMX_ErrorNone; |
| mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; |
| mm_jpeg_dim_t *dim = &p_jobparams->main_dim; |
| |
| if ((dim->crop.width == 0) || (dim->crop.height == 0)) { |
| dim->crop.width = dim->src_dim.width; |
| dim->crop.height = dim->src_dim.height; |
| } |
| /* error check first */ |
| if ((dim->crop.width + dim->crop.left > dim->src_dim.width) || |
| (dim->crop.height + dim->crop.top > dim->src_dim.height)) { |
| LOGE("invalid crop boundary (%d, %d) out of (%d, %d)", |
| dim->crop.width + dim->crop.left, |
| dim->crop.height + dim->crop.top, |
| dim->src_dim.width, |
| dim->src_dim.height); |
| return OMX_ErrorBadParameter; |
| } |
| |
| memset(&rect_type_in, 0, sizeof(rect_type_in)); |
| memset(&rect_type_out, 0, sizeof(rect_type_out)); |
| rect_type_in.nPortIndex = 0; |
| rect_type_out.nPortIndex = 0; |
| |
| if ((dim->src_dim.width != dim->crop.width) || |
| (dim->src_dim.height != dim->crop.height) || |
| (dim->src_dim.width != dim->dst_dim.width) || |
| (dim->src_dim.height != dim->dst_dim.height)) { |
| /* Scaler information */ |
| rect_type_in.nWidth = CEILING2(dim->crop.width); |
| rect_type_in.nHeight = CEILING2(dim->crop.height); |
| rect_type_in.nLeft = dim->crop.left; |
| rect_type_in.nTop = dim->crop.top; |
| |
| if (dim->dst_dim.width && dim->dst_dim.height) { |
| rect_type_out.nWidth = (OMX_U32)dim->dst_dim.width; |
| rect_type_out.nHeight = (OMX_U32)dim->dst_dim.height; |
| } |
| } |
| |
| ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonInputCrop, |
| &rect_type_in); |
| if (OMX_ErrorNone != ret) { |
| LOGE("Error"); |
| return ret; |
| } |
| |
| LOGH("OMX_IndexConfigCommonInputCrop w = %d, h = %d, l = %d, t = %d," |
| " port_idx = %d", |
| (int)rect_type_in.nWidth, (int)rect_type_in.nHeight, |
| (int)rect_type_in.nLeft, (int)rect_type_in.nTop, |
| (int)rect_type_in.nPortIndex); |
| |
| ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonOutputCrop, |
| &rect_type_out); |
| if (OMX_ErrorNone != ret) { |
| LOGE("Error"); |
| return ret; |
| } |
| LOGD("OMX_IndexConfigCommonOutputCrop w = %d, h = %d," |
| " port_idx = %d", |
| (int)rect_type_out.nWidth, (int)rect_type_out.nHeight, |
| (int)rect_type_out.nPortIndex); |
| |
| return ret; |
| } |
| |
| /** mm_jpeg_session_config_main: |
| * |
| * Arguments: |
| * @p_session: job session |
| * |
| * Return: |
| * OMX error values |
| * |
| * Description: |
| * Configure main image |
| * |
| **/ |
| OMX_ERRORTYPE mm_jpeg_session_config_main(mm_jpeg_job_session_t *p_session) |
| { |
| OMX_ERRORTYPE rc = OMX_ErrorNone; |
| |
| /* config port */ |
| LOGD("config port"); |
| rc = mm_jpeg_session_config_ports(p_session); |
| if (OMX_ErrorNone != rc) { |
| LOGE("config port failed"); |
| return rc; |
| } |
| |
| /* config buffer offset */ |
| LOGD("config main buf offset"); |
| rc = mm_jpeg_session_config_main_buffer_offset(p_session); |
| if (OMX_ErrorNone != rc) { |
| LOGE("config buffer offset failed"); |
| return rc; |
| } |
| |
| /* set the encoding mode */ |
| rc = mm_jpeg_encoding_mode(p_session); |
| if (OMX_ErrorNone != rc) { |
| LOGE("config encoding mode failed"); |
| return rc; |
| } |
| |
| /* set the metadata encrypt key */ |
| rc = mm_jpeg_meta_enc_key(p_session); |
| if (OMX_ErrorNone != rc) { |
| LOGE("config session failed"); |
| return rc; |
| } |
| |
| /* set the mem ops */ |
| rc = mm_jpeg_mem_ops(p_session); |
| if (OMX_ErrorNone != rc) { |
| LOGE("config mem ops failed"); |
| return rc; |
| } |
| /* set the jpeg speed mode */ |
| rc = mm_jpeg_speed_mode(p_session); |
| if (OMX_ErrorNone != rc) { |
| LOGE("config speed mode failed"); |
| return rc; |
| } |
| |
| return rc; |
| } |
| |
| /** mm_jpeg_session_config_common: |
| * |
| * Arguments: |
| * @p_session: job session |
| * |
| * Return: |
| * OMX error values |
| * |
| * Description: |
| * Configure common parameters |
| * |
| **/ |
| OMX_ERRORTYPE mm_jpeg_session_config_common(mm_jpeg_job_session_t *p_session) |
| { |
| OMX_ERRORTYPE rc = OMX_ErrorNone; |
| OMX_INDEXTYPE exif_idx; |
| OMX_CONFIG_ROTATIONTYPE rotate; |
| mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; |
| QOMX_EXIF_INFO exif_info; |
| |
| /* set rotation */ |
| memset(&rotate, 0, sizeof(rotate)); |
| rotate.nPortIndex = 1; |
| |
| if (p_session->lib2d_rotation_flag) { |
| rotate.nRotation = 0; |
| } else { |
| rotate.nRotation = (OMX_S32)p_jobparams->rotation; |
| } |
| |
| rc = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonRotate, |
| &rotate); |
| if (OMX_ErrorNone != rc) { |
| LOGE("Error %d", rc); |
| return rc; |
| } |
| LOGD("Set rotation to %d at port_idx = %d", |
| (int)p_jobparams->rotation, (int)rotate.nPortIndex); |
| |
| /* Set Exif data*/ |
| memset(&p_session->exif_info_local[0], 0, sizeof(p_session->exif_info_local)); |
| rc = OMX_GetExtensionIndex(p_session->omx_handle, QOMX_IMAGE_EXT_EXIF_NAME, |
| &exif_idx); |
| if (OMX_ErrorNone != rc) { |
| LOGE("Error %d", rc); |
| return rc; |
| } |
| |
| LOGD("Num of exif entries passed from HAL: %d", |
| (int)p_jobparams->exif_info.numOfEntries); |
| if (p_jobparams->exif_info.numOfEntries > 0) { |
| rc = OMX_SetConfig(p_session->omx_handle, exif_idx, |
| &p_jobparams->exif_info); |
| if (OMX_ErrorNone != rc) { |
| LOGE("Error %d", rc); |
| return rc; |
| } |
| } |
| /*parse aditional exif data from the metadata*/ |
| exif_info.numOfEntries = 0; |
| exif_info.exif_data = &p_session->exif_info_local[0]; |
| process_meta_data(p_jobparams->p_metadata, &exif_info, |
| &p_jobparams->cam_exif_params, p_jobparams->hal_version); |
| /* After Parse metadata */ |
| p_session->exif_count_local = (int)exif_info.numOfEntries; |
| |
| if (exif_info.numOfEntries > 0) { |
| /* set exif tags */ |
| LOGD("exif tags from metadata count %d", |
| (int)exif_info.numOfEntries); |
| |
| rc = OMX_SetConfig(p_session->omx_handle, exif_idx, |
| &exif_info); |
| if (OMX_ErrorNone != rc) { |
| LOGE("Error %d", rc); |
| return rc; |
| } |
| } |
| |
| return rc; |
| } |
| |
| /** mm_jpeg_session_abort: |
| * |
| * Arguments: |
| * @p_session: jpeg session |
| * |
| * Return: |
| * OMX_BOOL |
| * |
| * Description: |
| * Abort ongoing job |
| * |
| **/ |
| OMX_BOOL mm_jpeg_session_abort(mm_jpeg_job_session_t *p_session) |
| { |
| OMX_ERRORTYPE ret = OMX_ErrorNone; |
| int rc = 0; |
| |
| LOGD("E"); |
| pthread_mutex_lock(&p_session->lock); |
| if (MM_JPEG_ABORT_NONE != p_session->abort_state) { |
| pthread_mutex_unlock(&p_session->lock); |
| LOGH("**** ALREADY ABORTED"); |
| return 0; |
| } |
| p_session->abort_state = MM_JPEG_ABORT_INIT; |
| if (OMX_TRUE == p_session->encoding) { |
| p_session->state_change_pending = OMX_TRUE; |
| |
| LOGH("**** ABORTING"); |
| pthread_mutex_unlock(&p_session->lock); |
| |
| ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandStateSet, |
| OMX_StateIdle, NULL); |
| |
| if (ret != OMX_ErrorNone) { |
| LOGE("OMX_SendCommand returned error %d", ret); |
| return 1; |
| } |
| rc = mm_jpegenc_destroy_job(p_session); |
| if (rc != 0) { |
| LOGE("Destroy job returned error %d", rc); |
| } |
| |
| pthread_mutex_lock(&p_session->lock); |
| if (MM_JPEG_ABORT_INIT == p_session->abort_state) { |
| LOGL("before wait"); |
| pthread_cond_wait(&p_session->cond, &p_session->lock); |
| } |
| LOGL("after wait"); |
| } |
| p_session->abort_state = MM_JPEG_ABORT_DONE; |
| |
| mm_jpeg_put_mem((void *)p_session); |
| |
| pthread_mutex_unlock(&p_session->lock); |
| |
| // Abort next session |
| if (p_session->next_session) { |
| mm_jpeg_session_abort(p_session->next_session); |
| } |
| |
| LOGD("X"); |
| return 0; |
| } |
| |
| /** mm_jpeg_config_multi_image_info |
| * |
| * Arguments: |
| * @p_session: encode session |
| * |
| * Return: OMX_ERRORTYPE |
| * |
| * Description: |
| * Configure multi image parameters |
| * |
| **/ |
| static OMX_ERRORTYPE mm_jpeg_config_multi_image_info( |
| mm_jpeg_job_session_t *p_session) |
| { |
| OMX_ERRORTYPE ret = OMX_ErrorNone; |
| QOMX_JPEG_MULTI_IMAGE_INFO multi_image_info; |
| OMX_INDEXTYPE multi_image_index; |
| mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; |
| |
| ret = OMX_GetExtensionIndex(p_session->omx_handle, |
| QOMX_IMAGE_EXT_MULTI_IMAGE_NAME, &multi_image_index); |
| if (ret) { |
| LOGE("Error getting multi image info extention index %d", ret); |
| return ret; |
| } |
| memset(&multi_image_info, 0, sizeof(multi_image_info)); |
| if (p_jobparams->multi_image_info.type == MM_JPEG_TYPE_MPO) { |
| multi_image_info.image_type = QOMX_JPEG_IMAGE_TYPE_MPO; |
| } else { |
| multi_image_info.image_type = QOMX_JPEG_IMAGE_TYPE_JPEG; |
| } |
| multi_image_info.is_primary_image = p_jobparams->multi_image_info.is_primary; |
| multi_image_info.num_of_images = p_jobparams->multi_image_info.num_of_images; |
| multi_image_info.enable_metadata = p_jobparams->multi_image_info.enable_metadata; |
| |
| ret = OMX_SetConfig(p_session->omx_handle, multi_image_index, |
| &multi_image_info); |
| if (ret) { |
| LOGE("Error setting multi image config"); |
| return ret; |
| } |
| return ret; |
| } |
| |
| /** mm_jpeg_configure_params |
| * |
| * Arguments: |
| * @p_session: encode session |
| * |
| * Return: |
| * none |
| * |
| * Description: |
| * Configure the job specific params |
| * |
| **/ |
| static OMX_ERRORTYPE mm_jpeg_configure_job_params( |
| mm_jpeg_job_session_t *p_session) |
| { |
| OMX_ERRORTYPE ret = OMX_ErrorNone; |
| OMX_IMAGE_PARAM_QFACTORTYPE q_factor; |
| QOMX_WORK_BUFFER work_buffer; |
| OMX_INDEXTYPE work_buffer_index; |
| mm_jpeg_encode_params_t *p_params = &p_session->params; |
| mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; |
| int i; |
| |
| /* common config */ |
| ret = mm_jpeg_session_config_common(p_session); |
| if (OMX_ErrorNone != ret) { |
| LOGE("config common failed"); |
| } |
| |
| /* config Main Image crop */ |
| LOGD("config main crop"); |
| ret = mm_jpeg_session_config_main_crop(p_session); |
| if (OMX_ErrorNone != ret) { |
| LOGE("config crop failed"); |
| return ret; |
| } |
| |
| /* set quality */ |
| memset(&q_factor, 0, sizeof(q_factor)); |
| q_factor.nPortIndex = 0; |
| q_factor.nQFactor = p_params->quality; |
| ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexParamQFactor, &q_factor); |
| LOGD("config QFactor: %d", (int)q_factor.nQFactor); |
| if (OMX_ErrorNone != ret) { |
| LOGE("Error setting Q factor %d", ret); |
| return ret; |
| } |
| |
| /* config thumbnail */ |
| ret = mm_jpeg_session_config_thumbnail(p_session); |
| if (OMX_ErrorNone != ret) { |
| LOGE("config thumbnail img failed"); |
| return ret; |
| } |
| |
| //Pass the ION buffer to be used as o/p for HW |
| memset(&work_buffer, 0x0, sizeof(QOMX_WORK_BUFFER)); |
| ret = OMX_GetExtensionIndex(p_session->omx_handle, |
| QOMX_IMAGE_EXT_WORK_BUFFER_NAME, |
| &work_buffer_index); |
| if (ret) { |
| LOGE("Error getting work buffer index %d", ret); |
| return ret; |
| } |
| work_buffer.fd = p_session->work_buffer.p_pmem_fd; |
| work_buffer.vaddr = p_session->work_buffer.addr; |
| work_buffer.length = (uint32_t)p_session->work_buffer.size; |
| LOGH("Work buffer info %d %p WorkBufSize: %d invalidate", |
| work_buffer.fd, work_buffer.vaddr, work_buffer.length); |
| |
| buffer_invalidate(&p_session->work_buffer); |
| |
| ret = OMX_SetConfig(p_session->omx_handle, work_buffer_index, |
| &work_buffer); |
| if (ret) { |
| LOGE("Error"); |
| return ret; |
| } |
| |
| /* set metadata */ |
| ret = mm_jpeg_metadata(p_session); |
| if (OMX_ErrorNone != ret) { |
| LOGE("config makernote data failed"); |
| return ret; |
| } |
| |
| /* set QTable */ |
| for (i = 0; i < QTABLE_MAX; i++) { |
| if (p_jobparams->qtable_set[i]) { |
| ret = OMX_SetConfig(p_session->omx_handle, |
| OMX_IndexParamQuantizationTable, &p_jobparams->qtable[i]); |
| if (OMX_ErrorNone != ret) { |
| LOGE("set QTable Error"); |
| return ret; |
| } |
| } |
| } |
| |
| /* Set multi image data*/ |
| ret = mm_jpeg_config_multi_image_info(p_session); |
| if (OMX_ErrorNone != ret) { |
| LOGE("config multi image data failed"); |
| return ret; |
| } |
| |
| return ret; |
| } |
| |
| /** mm_jpeg_session_configure: |
| * |
| * Arguments: |
| * @data: encode session |
| * |
| * Return: |
| * none |
| * |
| * Description: |
| * Configure the session |
| * |
| **/ |
| static OMX_ERRORTYPE mm_jpeg_session_configure(mm_jpeg_job_session_t *p_session) |
| { |
| OMX_ERRORTYPE ret = OMX_ErrorNone; |
| |
| LOGD("E "); |
| |
| MM_JPEG_CHK_ABORT(p_session, ret, error); |
| |
| /* config main img */ |
| ret = mm_jpeg_session_config_main(p_session); |
| if (OMX_ErrorNone != ret) { |
| LOGE("config main img failed"); |
| goto error; |
| } |
| ret = mm_jpeg_session_change_state(p_session, OMX_StateIdle, |
| mm_jpeg_session_send_buffers); |
| if (ret) { |
| LOGE("change state to idle failed %d", ret); |
| goto error; |
| } |
| |
| ret = mm_jpeg_session_change_state(p_session, OMX_StateExecuting, |
| NULL); |
| if (ret) { |
| LOGE("change state to executing failed %d", ret); |
| goto error; |
| } |
| |
| error: |
| LOGD("X ret %d", ret); |
| return ret; |
| } |
| |
| |
| |
| |
| |
| |
| /** mm_jpeg_session_encode: |
| * |
| * Arguments: |
| * @p_session: encode session |
| * |
| * Return: |
| * OMX_ERRORTYPE |
| * |
| * Description: |
| * Start the encoding |
| * |
| **/ |
| static OMX_ERRORTYPE mm_jpeg_session_encode(mm_jpeg_job_session_t *p_session) |
| { |
| OMX_ERRORTYPE ret = OMX_ErrorNone; |
| mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; |
| mm_jpeg_obj *my_obj = (mm_jpeg_obj *) p_session->jpeg_obj; |
| OMX_BUFFERHEADERTYPE *p_in_buf = NULL; |
| OMX_BUFFERHEADERTYPE *p_in_thumb_buf = NULL; |
| |
| pthread_mutex_lock(&p_session->lock); |
| p_session->abort_state = MM_JPEG_ABORT_NONE; |
| p_session->encoding = OMX_FALSE; |
| pthread_mutex_unlock(&p_session->lock); |
| |
| if (p_session->thumb_from_main) { |
| if (0 > p_jobparams->src_index) { |
| LOGE("Error"); |
| ret = OMX_ErrorUnsupportedIndex; |
| goto error; |
| } |
| p_jobparams->thumb_index = (uint32_t)p_jobparams->src_index; |
| p_jobparams->thumb_dim.crop = p_jobparams->main_dim.crop; |
| } |
| |
| if (OMX_FALSE == p_session->config) { |
| /* If another session in progress clear that sessions configuration */ |
| if (my_obj->p_session_inprogress != NULL) { |
| OMX_STATETYPE state; |
| mm_jpeg_job_session_t *p_session_inprogress = my_obj->p_session_inprogress; |
| |
| OMX_GetState(p_session_inprogress->omx_handle, &state); |
| |
| //Check state before state transition |
| if ((state == OMX_StateExecuting) || (state == OMX_StatePause)) { |
| ret = mm_jpeg_session_change_state(p_session_inprogress, |
| OMX_StateIdle, NULL); |
| if (ret) { |
| LOGE("Error"); |
| goto error; |
| } |
| } |
| |
| OMX_GetState(p_session_inprogress->omx_handle, &state); |
| |
| if (state == OMX_StateIdle) { |
| ret = mm_jpeg_session_change_state(p_session_inprogress, |
| OMX_StateLoaded, mm_jpeg_session_free_buffers); |
| if (ret) { |
| LOGE("Error"); |
| goto error; |
| } |
| } |
| p_session_inprogress->config = OMX_FALSE; |
| my_obj->p_session_inprogress = NULL; |
| } |
| |
| ret = mm_jpeg_session_configure(p_session); |
| if (ret) { |
| LOGE("Error"); |
| goto error; |
| } |
| p_session->config = OMX_TRUE; |
| my_obj->p_session_inprogress = p_session; |
| } |
| |
| ret = mm_jpeg_configure_job_params(p_session); |
| if (ret) { |
| LOGE("Error"); |
| goto error; |
| } |
| pthread_mutex_lock(&p_session->lock); |
| p_session->encoding = OMX_TRUE; |
| pthread_mutex_unlock(&p_session->lock); |
| |
| MM_JPEG_CHK_ABORT(p_session, ret, error); |
| |
| if (p_session->lib2d_rotation_flag) { |
| p_in_buf = p_session->p_in_rot_omx_buf[p_jobparams->src_index]; |
| } else { |
| p_in_buf = p_session->p_in_omx_buf[p_jobparams->src_index]; |
| } |
| |
| #ifdef MM_JPEG_DUMP_INPUT |
| char filename[256]; |
| snprintf(filename, sizeof(filename), |
| QCAMERA_DUMP_FRM_LOCATION"jpeg/mm_jpeg_int%d.yuv", p_session->ebd_count); |
| DUMP_TO_FILE(filename, p_in_buf->pBuffer, (size_t)p_in_buf->nAllocLen); |
| #endif |
| ret = OMX_EmptyThisBuffer(p_session->omx_handle, p_in_buf); |
| if (ret) { |
| LOGE("Error"); |
| goto error; |
| } |
| |
| if (p_session->params.encode_thumbnail) { |
| |
| if (p_session->thumb_from_main && |
| p_session->lib2d_rotation_flag) { |
| p_in_thumb_buf = p_session->p_in_rot_omx_thumb_buf[p_jobparams->thumb_index]; |
| } else { |
| p_in_thumb_buf = p_session->p_in_omx_thumb_buf[p_jobparams->thumb_index]; |
| } |
| |
| #ifdef MM_JPEG_DUMP_INPUT |
| char thumb_filename[FILENAME_MAX]; |
| snprintf(thumb_filename, sizeof(thumb_filename), |
| QCAMERA_DUMP_FRM_LOCATION"jpeg/mm_jpeg_int_t%d.yuv", p_session->ebd_count); |
| DUMP_TO_FILE(filename, p_in_thumb_buf->pBuffer, |
| (size_t)p_in_thumb_buf->nAllocLen); |
| #endif |
| ret = OMX_EmptyThisBuffer(p_session->omx_handle, p_in_thumb_buf); |
| if (ret) { |
| LOGE("Error"); |
| goto error; |
| } |
| } |
| |
| ret = OMX_FillThisBuffer(p_session->omx_handle, |
| p_session->p_out_omx_buf[p_jobparams->dst_index]); |
| if (ret) { |
| LOGE("Error"); |
| goto error; |
| } |
| |
| MM_JPEG_CHK_ABORT(p_session, ret, error); |
| |
| error: |
| |
| LOGD("X "); |
| return ret; |
| } |
| |
| /** mm_jpeg_process_encoding_job: |
| * |
| * Arguments: |
| * @my_obj: jpeg client |
| * @job_node: job node |
| * |
| * Return: |
| * 0 for success -1 otherwise |
| * |
| * Description: |
| * Start the encoding job |
| * |
| **/ |
| int32_t mm_jpeg_process_encoding_job(mm_jpeg_obj *my_obj, mm_jpeg_job_q_node_t* job_node) |
| { |
| mm_jpeg_q_data_t qdata; |
| int32_t rc = 0; |
| OMX_ERRORTYPE ret = OMX_ErrorNone; |
| mm_jpeg_job_session_t *p_session = NULL; |
| uint32_t buf_idx; |
| |
| /* check if valid session */ |
| p_session = mm_jpeg_get_session(my_obj, job_node->enc_info.job_id); |
| if (NULL == p_session) { |
| LOGE("invalid job id %x", |
| job_node->enc_info.job_id); |
| return -1; |
| } |
| |
| LOGD("before dequeue session %d", ret); |
| |
| /* dequeue available omx handle */ |
| qdata = mm_jpeg_queue_deq(p_session->session_handle_q); |
| p_session = qdata.p; |
| |
| if (NULL == p_session) { |
| LOGH("No available sessions %d", ret); |
| /* No available handles */ |
| qdata.p = job_node; |
| mm_jpeg_queue_enq_head(&my_obj->job_mgr.job_queue, qdata); |
| |
| LOGH("end enqueue %d", ret); |
| return rc; |
| |
| } |
| |
| p_session->auto_out_buf = OMX_FALSE; |
| if (job_node->enc_info.encode_job.dst_index < 0) { |
| /* dequeue available output buffer idx */ |
| qdata = mm_jpeg_queue_deq(p_session->out_buf_q); |
| buf_idx = qdata.u32; |
| |
| if (0U == buf_idx) { |
| LOGE("No available output buffers %d", ret); |
| return OMX_ErrorUndefined; |
| } |
| |
| buf_idx--; |
| |
| job_node->enc_info.encode_job.dst_index = (int32_t)buf_idx; |
| p_session->auto_out_buf = OMX_TRUE; |
| } |
| |
| /* sent encode cmd to OMX, queue job into ongoing queue */ |
| qdata.p = job_node; |
| rc = mm_jpeg_queue_enq(&my_obj->ongoing_job_q, qdata); |
| if (rc) { |
| LOGE("jpeg enqueue failed %d", ret); |
| goto error; |
| } |
| |
| p_session->encode_job = job_node->enc_info.encode_job; |
| p_session->jobId = job_node->enc_info.job_id; |
| ret = mm_jpeg_session_encode(p_session); |
| if (ret) { |
| LOGE("encode session failed"); |
| goto error; |
| } |
| |
| LOGH("Success X "); |
| return rc; |
| |
| error: |
| |
| if ((OMX_ErrorNone != ret) && |
| (NULL != p_session->params.jpeg_cb)) { |
| p_session->job_status = JPEG_JOB_STATUS_ERROR; |
| LOGE("send jpeg error callback %d", |
| p_session->job_status); |
| p_session->params.jpeg_cb(p_session->job_status, |
| p_session->client_hdl, |
| p_session->jobId, |
| NULL, |
| p_session->params.userdata); |
| } |
| |
| /*remove the job*/ |
| mm_jpegenc_job_done(p_session); |
| LOGD("Error X "); |
| |
| return rc; |
| } |
| |
| |
| |
| /** mm_jpeg_jobmgr_thread: |
| * |
| * Arguments: |
| * @my_obj: jpeg object |
| * |
| * Return: |
| * 0 for success else failure |
| * |
| * Description: |
| * job manager thread main function |
| * |
| **/ |
| static void *mm_jpeg_jobmgr_thread(void *data) |
| { |
| mm_jpeg_q_data_t qdata; |
| int rc = 0; |
| int running = 1; |
| uint32_t num_ongoing_jobs = 0; |
| mm_jpeg_obj *my_obj = (mm_jpeg_obj*)data; |
| mm_jpeg_job_cmd_thread_t *cmd_thread = &my_obj->job_mgr; |
| mm_jpeg_job_q_node_t* node = NULL; |
| prctl(PR_SET_NAME, (unsigned long)"mm_jpeg_thread", 0, 0, 0); |
| |
| do { |
| do { |
| rc = cam_sem_wait(&cmd_thread->job_sem); |
| if (rc != 0 && errno != EINVAL) { |
| LOGE("cam_sem_wait error (%s)", |
| strerror(errno)); |
| return NULL; |
| } |
| } while (rc != 0); |
| |
| /* check ongoing q size */ |
| num_ongoing_jobs = mm_jpeg_queue_get_size(&my_obj->ongoing_job_q); |
| |
| LOGD("ongoing job %d %d", num_ongoing_jobs, MM_JPEG_CONCURRENT_SESSIONS_COUNT); |
| if (num_ongoing_jobs >= MM_JPEG_CONCURRENT_SESSIONS_COUNT) { |
| LOGE("ongoing job already reach max %d", num_ongoing_jobs); |
| continue; |
| } |
| |
| pthread_mutex_lock(&my_obj->job_lock); |
| /* can go ahead with new work */ |
| qdata = mm_jpeg_queue_deq(&cmd_thread->job_queue); |
| node = (mm_jpeg_job_q_node_t*)qdata.p; |
| if (node != NULL) { |
| switch (node->type) { |
| case MM_JPEG_CMD_TYPE_JOB: |
| rc = mm_jpeg_process_encoding_job(my_obj, node); |
| break; |
| case MM_JPEG_CMD_TYPE_DECODE_JOB: |
| rc = mm_jpegdec_process_decoding_job(my_obj, node); |
| break; |
| case MM_JPEG_CMD_TYPE_EXIT: |
| default: |
| /* free node */ |
| free(node); |
| /* set running flag to false */ |
| running = 0; |
| break; |
| } |
| } |
| pthread_mutex_unlock(&my_obj->job_lock); |
| |
| } while (running); |
| return NULL; |
| } |
| |
| /** mm_jpeg_jobmgr_thread_launch: |
| * |
| * Arguments: |
| * @my_obj: jpeg object |
| * |
| * Return: |
| * 0 for success else failure |
| * |
| * Description: |
| * launches the job manager thread |
| * |
| **/ |
| int32_t mm_jpeg_jobmgr_thread_launch(mm_jpeg_obj *my_obj) |
| { |
| int32_t rc = 0; |
| mm_jpeg_job_cmd_thread_t *job_mgr = &my_obj->job_mgr; |
| |
| cam_sem_init(&job_mgr->job_sem, 0); |
| mm_jpeg_queue_init(&job_mgr->job_queue); |
| |
| /* launch the thread */ |
| pthread_create(&job_mgr->pid, |
| NULL, |
| mm_jpeg_jobmgr_thread, |
| (void *)my_obj); |
| pthread_setname_np(job_mgr->pid, "CAM_jpeg_jobmgr"); |
| return rc; |
| } |
| |
| /** mm_jpeg_jobmgr_thread_release: |
| * |
| * Arguments: |
| * @my_obj: jpeg object |
| * |
| * Return: |
| * 0 for success else failure |
| * |
| * Description: |
| * Releases the job manager thread |
| * |
| **/ |
| int32_t mm_jpeg_jobmgr_thread_release(mm_jpeg_obj * my_obj) |
| { |
| mm_jpeg_q_data_t qdata; |
| int32_t rc = 0; |
| mm_jpeg_job_cmd_thread_t * cmd_thread = &my_obj->job_mgr; |
| mm_jpeg_job_q_node_t* node = |
| (mm_jpeg_job_q_node_t *)malloc(sizeof(mm_jpeg_job_q_node_t)); |
| if (NULL == node) { |
| LOGE("No memory for mm_jpeg_job_q_node_t"); |
| return -1; |
| } |
| |
| memset(node, 0, sizeof(mm_jpeg_job_q_node_t)); |
| node->type = MM_JPEG_CMD_TYPE_EXIT; |
| |
| qdata.p = node; |
| mm_jpeg_queue_enq(&cmd_thread->job_queue, qdata); |
| cam_sem_post(&cmd_thread->job_sem); |
| |
| /* wait until cmd thread exits */ |
| if (pthread_join(cmd_thread->pid, NULL) != 0) { |
| LOGD("pthread dead already"); |
| } |
| mm_jpeg_queue_deinit(&cmd_thread->job_queue); |
| |
| cam_sem_destroy(&cmd_thread->job_sem); |
| memset(cmd_thread, 0, sizeof(mm_jpeg_job_cmd_thread_t)); |
| return rc; |
| } |
| |
| /** mm_jpeg_alloc_workbuffer: |
| * |
| * Arguments: |
| * @my_obj: jpeg object |
| * @work_bufs_need: number of work buffers required |
| * @work_buf_size: size of the work buffer |
| * |
| * Return: |
| * greater or equal to 0 for success else failure |
| * |
| * Description: |
| * Allocates work buffer |
| * |
| **/ |
| int32_t mm_jpeg_alloc_workbuffer(mm_jpeg_obj *my_obj, |
| uint32_t work_bufs_need, |
| uint32_t work_buf_size) |
| { |
| int32_t rc = 0; |
| uint32_t i; |
| LOGH("work_bufs_need %d work_buf_cnt %d", |
| work_bufs_need, my_obj->work_buf_cnt); |
| for (i = my_obj->work_buf_cnt; i < work_bufs_need; i++) { |
| my_obj->ionBuffer[i].size = CEILING32(work_buf_size); |
| LOGH("Max picture size %d x %d, WorkBufSize = %zu", |
| my_obj->max_pic_w, my_obj->max_pic_h, my_obj->ionBuffer[i].size); |
| my_obj->ionBuffer[i].addr = (uint8_t *)buffer_allocate(&my_obj->ionBuffer[i], 1); |
| if (NULL == my_obj->ionBuffer[i].addr) { |
| LOGE("Ion allocation failed"); |
| while (i--) { |
| buffer_deallocate(&my_obj->ionBuffer[i]); |
| my_obj->work_buf_cnt--; |
| } |
| return -1; |
| } |
| my_obj->work_buf_cnt++; |
| rc = i; |
| } |
| LOGH("rc %d ", rc); |
| return rc; |
| } |
| |
| /** mm_jpeg_release_workbuffer: |
| * |
| * Arguments: |
| * @my_obj: jpeg object |
| * @work_bufs_need: number of work buffers allocated |
| * |
| * Return: |
| * 0 for success else failure |
| * |
| * Description: |
| * Releases the allocated work buffer |
| * |
| **/ |
| int32_t mm_jpeg_release_workbuffer(mm_jpeg_obj *my_obj, |
| uint32_t work_bufs_need) |
| { |
| int32_t rc = 0; |
| uint32_t i; |
| LOGH("release work_bufs %d ", work_bufs_need); |
| for (i = my_obj->work_buf_cnt; i < work_bufs_need; i++) { |
| buffer_deallocate(&my_obj->ionBuffer[i]); |
| } |
| return rc; |
| } |
| |
| /** mm_jpeg_init: |
| * |
| * Arguments: |
| * @my_obj: jpeg object |
| * |
| * Return: |
| * 0 for success else failure |
| * |
| * Description: |
| * Initializes the jpeg client |
| * |
| **/ |
| int32_t mm_jpeg_init(mm_jpeg_obj *my_obj) |
| { |
| int32_t rc = 0; |
| uint32_t work_buf_size; |
| unsigned int initial_workbufs_cnt = 1; |
| |
| /* init locks */ |
| pthread_mutex_init(&my_obj->job_lock, NULL); |
| |
| /* init ongoing job queue */ |
| rc = mm_jpeg_queue_init(&my_obj->ongoing_job_q); |
| if (0 != rc) { |
| LOGE("Error"); |
| pthread_mutex_destroy(&my_obj->job_lock); |
| return -1; |
| } |
| |
| |
| /* init job semaphore and launch jobmgr thread */ |
| LOGD("Launch jobmgr thread rc %d", rc); |
| rc = mm_jpeg_jobmgr_thread_launch(my_obj); |
| if (0 != rc) { |
| LOGE("Error"); |
| mm_jpeg_queue_deinit(&my_obj->ongoing_job_q); |
| pthread_mutex_destroy(&my_obj->job_lock); |
| return -1; |
| } |
| |
| /* set work buf size from max picture size */ |
| if (my_obj->max_pic_w <= 0 || my_obj->max_pic_h <= 0) { |
| LOGE("Width and height are not valid " |
| "dimensions, cannot calc work buf size"); |
| mm_jpeg_jobmgr_thread_release(my_obj); |
| mm_jpeg_queue_deinit(&my_obj->ongoing_job_q); |
| pthread_mutex_destroy(&my_obj->job_lock); |
| return -1; |
| } |
| |
| /* allocate work buffer if reproc source buffer is not supposed to be used */ |
| if (!my_obj->reuse_reproc_buffer) { |
| work_buf_size = CEILING64((uint32_t)my_obj->max_pic_w) * |
| CEILING64((uint32_t)my_obj->max_pic_h) * 3U / 2U; |
| rc = mm_jpeg_alloc_workbuffer(my_obj, initial_workbufs_cnt, work_buf_size); |
| if (rc == -1) { |
| LOGE("Work buffer allocation failure"); |
| return rc; |
| } |
| } |
| |
| /* load OMX */ |
| if (OMX_ErrorNone != OMX_Init()) { |
| /* roll back in error case */ |
| LOGE("OMX_Init failed (%d)", rc); |
| if (!my_obj->reuse_reproc_buffer) { |
| mm_jpeg_release_workbuffer(my_obj, initial_workbufs_cnt); |
| } |
| mm_jpeg_jobmgr_thread_release(my_obj); |
| mm_jpeg_queue_deinit(&my_obj->ongoing_job_q); |
| pthread_mutex_destroy(&my_obj->job_lock); |
| } |
| |
| #ifdef LOAD_ADSP_RPC_LIB |
| my_obj->adsprpc_lib_handle = dlopen("libadsprpc.so", RTLD_NOW); |
| if (NULL == my_obj->adsprpc_lib_handle) { |
| LOGE("Cannot load the library"); |
| /* not returning error here bcoz even if this loading fails |
| we can go ahead with SW JPEG enc */ |
| } |
| #endif |
| |
| // create dummy OMX handle to avoid dlopen latency |
| OMX_GetHandle(&my_obj->dummy_handle, mm_jpeg_get_comp_name(), NULL, NULL); |
| |
| return rc; |
| } |
| |
| /** mm_jpeg_deinit: |
| * |
| * Arguments: |
| * @my_obj: jpeg object |
| * |
| * Return: |
| * 0 for success else failure |
| * |
| * Description: |
| * Deinits the jpeg client |
| * |
| **/ |
| int32_t mm_jpeg_deinit(mm_jpeg_obj *my_obj) |
| { |
| int32_t rc = 0; |
| uint32_t i = 0; |
| |
| /* release jobmgr thread */ |
| rc = mm_jpeg_jobmgr_thread_release(my_obj); |
| if (0 != rc) { |
| LOGE("Error"); |
| } |
| |
| if (my_obj->dummy_handle) { |
| OMX_FreeHandle(my_obj->dummy_handle); |
| } |
| |
| /* unload OMX engine */ |
| OMX_Deinit(); |
| |
| /* deinit ongoing job and cb queue */ |
| rc = mm_jpeg_queue_deinit(&my_obj->ongoing_job_q); |
| if (0 != rc) { |
| LOGE("Error"); |
| } |
| |
| for (i = 0; i < my_obj->work_buf_cnt; i++) { |
| /*Release the ION buffer*/ |
| rc = buffer_deallocate(&my_obj->ionBuffer[i]); |
| if (0 != rc) { |
| LOGE("Error releasing ION buffer"); |
| } |
| } |
| my_obj->work_buf_cnt = 0; |
| my_obj->jpeg_metadata = NULL; |
| |
| /* destroy locks */ |
| pthread_mutex_destroy(&my_obj->job_lock); |
| |
| return rc; |
| } |
| |
| /** mm_jpeg_new_client: |
| * |
| * Arguments: |
| * @my_obj: jpeg object |
| * |
| * Return: |
| * 0 for success else failure |
| * |
| * Description: |
| * Create new jpeg client |
| * |
| **/ |
| uint32_t mm_jpeg_new_client(mm_jpeg_obj *my_obj) |
| { |
| uint32_t client_hdl = 0; |
| uint8_t idx; |
| int i = 0; |
| |
| if (my_obj->num_clients >= MAX_JPEG_CLIENT_NUM) { |
| LOGE("num of clients reached limit"); |
| return client_hdl; |
| } |
| |
| for (idx = 0; idx < MAX_JPEG_CLIENT_NUM; idx++) { |
| if (0 == my_obj->clnt_mgr[idx].is_used) { |
| break; |
| } |
| } |
| |
| if (idx < MAX_JPEG_CLIENT_NUM) { |
| /* client session avail */ |
| /* generate client handler by index */ |
| client_hdl = mm_jpeg_util_generate_handler(idx); |
| |
| /* update client session */ |
| my_obj->clnt_mgr[idx].is_used = 1; |
| my_obj->clnt_mgr[idx].client_handle = client_hdl; |
| |
| pthread_mutex_init(&my_obj->clnt_mgr[idx].lock, NULL); |
| for (i = 0; i < MM_JPEG_MAX_SESSION; i++) { |
| memset(&my_obj->clnt_mgr[idx].session[i], 0x0, sizeof(mm_jpeg_job_session_t)); |
| } |
| |
| /* increse client count */ |
| my_obj->num_clients++; |
| } |
| |
| return client_hdl; |
| } |
| |
| #ifdef LIB2D_ROTATION_ENABLE |
| /** |
| * Function: mm_jpeg_lib2d_rotation_cb |
| * |
| * Description: Callback that is called on completion of requested job. |
| * |
| * Input parameters: |
| * userdata - App userdata |
| * jobid - job id that is finished execution |
| * |
| * Return values: |
| * MM_LIB2D_SUCCESS |
| * MM_LIB2D_ERR_GENERAL |
| * |
| * Notes: none |
| **/ |
| lib2d_error mm_jpeg_lib2d_rotation_cb(void *userdata, int jobid) |
| { |
| LOGE("_GM_ Received CB from lib2d\n"); |
| return MM_LIB2D_SUCCESS; |
| } |
| |
| /** |
| * Function: mm_jpeg_lib2d_rotation |
| * |
| * Description: lib2d rotation function. |
| * |
| * Input parameters: |
| * p_session - pointer to session |
| * p_node - pointer to job queue node |
| * p_job - pointer to job |
| * p_job_id - pointer to job id |
| * |
| * Return values: |
| * 0 - success |
| * -1 - failure |
| * |
| * Notes: none |
| **/ |
| int32_t mm_jpeg_lib2d_rotation(mm_jpeg_job_session_t *p_session, |
| mm_jpeg_job_q_node_t* p_node, mm_jpeg_job_t *p_job, uint32_t *p_job_id) |
| { |
| void *lib2d_handle = NULL; |
| lib2d_error lib2d_err = MM_LIB2D_SUCCESS; |
| mm_lib2d_buffer src_buffer; |
| mm_lib2d_buffer dst_buffer; |
| mm_jpeg_buf_t *p_src_main_buf = p_session->params.src_main_buf; |
| mm_jpeg_buf_t *p_src_rot_main_buf = p_session->src_rot_main_buf; |
| mm_jpeg_encode_job_t *p_jobparams = &p_job->encode_job; |
| mm_jpeg_encode_job_t *p_jobparams_node = &p_node->enc_info.encode_job; |
| cam_format_t format; |
| int32_t scanline = 0; |
| |
| memset(&src_buffer, 0x0, sizeof(mm_lib2d_buffer)); |
| memset(&dst_buffer, 0x0, sizeof(mm_lib2d_buffer)); |
| |
| switch (p_session->params.rotation) { |
| case 0: |
| break; |
| case 90: |
| p_jobparams_node->main_dim.src_dim.width = |
| p_jobparams->main_dim.src_dim.height; |
| p_jobparams_node->main_dim.src_dim.height = |
| p_jobparams->main_dim.src_dim.width; |
| |
| p_jobparams_node->main_dim.dst_dim.width = |
| p_jobparams->main_dim.dst_dim.height; |
| p_jobparams_node->main_dim.dst_dim.height = |
| p_jobparams->main_dim.dst_dim.width; |
| |
| p_jobparams_node->main_dim.crop.width = |
| p_jobparams->main_dim.crop.height; |
| p_jobparams_node->main_dim.crop.height = |
| p_jobparams->main_dim.crop.width; |
| p_jobparams_node->main_dim.crop.left = |
| p_jobparams->main_dim.src_dim.height - |
| (p_jobparams->main_dim.crop.top + |
| p_jobparams->main_dim.crop.height); |
| p_jobparams_node->main_dim.crop.top = |
| p_jobparams->main_dim.crop.left; |
| break; |
| case 180: |
| p_jobparams_node->main_dim.crop.left = |
| p_jobparams->main_dim.src_dim.width - |
| (p_jobparams->main_dim.crop.left + |
| p_jobparams->main_dim.crop.width); |
| p_jobparams_node->main_dim.crop.top = |
| p_jobparams->main_dim.src_dim.height - |
| (p_jobparams->main_dim.crop.top + |
| p_jobparams->main_dim.crop.height); |
| break; |
| case 270: |
| p_jobparams_node->main_dim.src_dim.width = |
| p_jobparams->main_dim.src_dim.height; |
| p_jobparams_node->main_dim.src_dim.height = |
| p_jobparams->main_dim.src_dim.width; |
| |
| p_jobparams_node->main_dim.dst_dim.width = |
| p_jobparams->main_dim.dst_dim.height; |
| p_jobparams_node->main_dim.dst_dim.height = |
| p_jobparams->main_dim.dst_dim.width; |
| |
| p_jobparams_node->main_dim.crop.width = |
| p_jobparams->main_dim.crop.height; |
| p_jobparams_node->main_dim.crop.height = |
| p_jobparams->main_dim.crop.width; |
| p_jobparams_node->main_dim.crop.left = |
| p_jobparams->main_dim.crop.top; |
| p_jobparams_node->main_dim.crop.top = |
| p_jobparams->main_dim.src_dim.width - |
| (p_jobparams->main_dim.crop.left + |
| p_jobparams->main_dim.crop.width); |
| break; |
| } |
| |
| format = mm_jpeg_get_imgfmt_from_colorfmt(p_session->params.color_format); |
| lib2d_err = mm_lib2d_init(MM_LIB2D_SYNC_MODE, format, |
| format, &lib2d_handle); |
| if (lib2d_err != MM_LIB2D_SUCCESS) { |
| LOGE("lib2d init for rotation failed\n"); |
| return -1; |
| } |
| |
| src_buffer.buffer_type = MM_LIB2D_BUFFER_TYPE_YUV; |
| src_buffer.yuv_buffer.fd = |
| p_src_main_buf[p_jobparams->src_index].fd; |
| src_buffer.yuv_buffer.format = format; |
| src_buffer.yuv_buffer.width = p_jobparams->main_dim.src_dim.width; |
| src_buffer.yuv_buffer.height = p_jobparams->main_dim.src_dim.height; |
| src_buffer.yuv_buffer.plane0 = |
| p_src_main_buf[p_jobparams->src_index].buf_vaddr; |
| src_buffer.yuv_buffer.stride0 = |
| p_src_main_buf[p_jobparams->src_index].offset.mp[0].stride; |
| scanline = p_src_main_buf[p_jobparams->src_index].offset.mp[0].scanline; |
| src_buffer.yuv_buffer.plane1 = |
| (uint8_t*)src_buffer.yuv_buffer.plane0 + |
| (src_buffer.yuv_buffer.stride0 * scanline); |
| src_buffer.yuv_buffer.stride1 = src_buffer.yuv_buffer.stride0; |
| |
| LOGD(" lib2d SRC wxh = %dx%d , stxsl = %dx%d\n", |
| src_buffer.yuv_buffer.width, src_buffer.yuv_buffer.height, |
| src_buffer.yuv_buffer.stride0, scanline); |
| |
| dst_buffer.buffer_type = MM_LIB2D_BUFFER_TYPE_YUV; |
| dst_buffer.yuv_buffer.fd = |
| p_src_rot_main_buf[p_jobparams->src_index].fd; |
| dst_buffer.yuv_buffer.format = format; |
| dst_buffer.yuv_buffer.width = p_jobparams_node->main_dim.src_dim.width; |
| dst_buffer.yuv_buffer.height = p_jobparams_node->main_dim.src_dim.height; |
| dst_buffer.yuv_buffer.plane0 = |
| p_src_rot_main_buf[p_jobparams->src_index].buf_vaddr; |
| |
| if ((p_session->params.rotation == 90) || |
| (p_session->params.rotation == 270)) { |
| dst_buffer.yuv_buffer.stride0 = |
| p_src_main_buf[p_jobparams->src_index].offset.mp[0].scanline; |
| scanline = p_src_main_buf[p_jobparams->src_index].offset.mp[0].stride; |
| } else { |
| dst_buffer.yuv_buffer.stride0 = |
| p_src_main_buf[p_jobparams->src_index].offset.mp[0].stride; |
| scanline = p_src_main_buf[p_jobparams->src_index].offset.mp[0].scanline; |
| } |
| |
| dst_buffer.yuv_buffer.plane1 = |
| (uint8_t*) dst_buffer.yuv_buffer.plane0 + |
| (dst_buffer.yuv_buffer.stride0 * scanline); |
| dst_buffer.yuv_buffer.stride1 = dst_buffer.yuv_buffer.stride0; |
| |
| LOGD(" lib2d DEST wxh = %dx%d , stxsl = %dx%d\n", |
| dst_buffer.yuv_buffer.width, dst_buffer.yuv_buffer.height, |
| dst_buffer.yuv_buffer.stride0, scanline); |
| |
| LOGD(" lib2d rotation = %d\n", p_session->params.rotation); |
| |
| lib2d_err = mm_lib2d_start_job(lib2d_handle, &src_buffer, &dst_buffer, |
| *p_job_id, NULL, mm_jpeg_lib2d_rotation_cb, p_session->params.rotation); |
| if (lib2d_err != MM_LIB2D_SUCCESS) { |
| LOGE("Error in mm_lib2d_start_job \n"); |
| return -1; |
| } |
| |
| buffer_clean(&p_session->src_rot_ion_buffer[p_jobparams->src_index]); |
| |
| return 0; |
| } |
| #endif |
| |
| /** mm_jpeg_start_job: |
| * |
| * Arguments: |
| * @my_obj: jpeg object |
| * @client_hdl: client handle |
| * @job: pointer to encode job |
| * @jobId: job id |
| * |
| * Return: |
| * 0 for success else failure |
| * |
| * Description: |
| * Start the encoding job |
| * |
| **/ |
| int32_t mm_jpeg_start_job(mm_jpeg_obj *my_obj, |
| mm_jpeg_job_t *job, |
| uint32_t *job_id) |
| { |
| mm_jpeg_q_data_t qdata; |
| int32_t rc = -1; |
| uint8_t session_idx = 0; |
| uint8_t client_idx = 0; |
| mm_jpeg_job_q_node_t* node = NULL; |
| mm_jpeg_job_session_t *p_session = NULL; |
| mm_jpeg_encode_job_t *p_jobparams = NULL; |
| uint32_t work_bufs_need; |
| uint32_t work_buf_size; |
| |
| *job_id = 0; |
| |
| if (!job) { |
| LOGE("invalid job !!!"); |
| return rc; |
| } |
| p_jobparams = &job->encode_job; |
| |
| /* check if valid session */ |
| session_idx = GET_SESSION_IDX(p_jobparams->session_id); |
| client_idx = GET_CLIENT_IDX(p_jobparams->session_id); |
| LOGD("session_idx %d client idx %d", |
| session_idx, client_idx); |
| |
| if ((session_idx >= MM_JPEG_MAX_SESSION) || |
| (client_idx >= MAX_JPEG_CLIENT_NUM)) { |
| LOGE("invalid session id %x", |
| job->encode_job.session_id); |
| return rc; |
| } |
| |
| p_session = &my_obj->clnt_mgr[client_idx].session[session_idx]; |
| |
| if (my_obj->reuse_reproc_buffer) { |
| p_session->work_buffer.addr = p_jobparams->work_buf.buf_vaddr; |
| p_session->work_buffer.size = p_jobparams->work_buf.buf_size; |
| p_session->work_buffer.ion_info_fd.fd = p_jobparams->work_buf.fd; |
| p_session->work_buffer.p_pmem_fd = p_jobparams->work_buf.fd; |
| |
| work_bufs_need = my_obj->num_sessions + 1; |
| if (work_bufs_need > MM_JPEG_CONCURRENT_SESSIONS_COUNT) { |
| work_bufs_need = MM_JPEG_CONCURRENT_SESSIONS_COUNT; |
| } |
| |
| if (p_session->work_buffer.addr) { |
| work_bufs_need--; |
| LOGD("HAL passed the work buffer of size = %d; don't alloc internally", |
| p_session->work_buffer.size); |
| } else { |
| p_session->work_buffer = my_obj->ionBuffer[0]; |
| } |
| |
| LOGD(">>>> Work bufs need %d, %d", |
| work_bufs_need, my_obj->work_buf_cnt); |
| if (work_bufs_need) { |
| work_buf_size = CEILING64(my_obj->max_pic_w) * |
| CEILING64(my_obj->max_pic_h) * 3 / 2; |
| rc = mm_jpeg_alloc_workbuffer(my_obj, work_bufs_need, work_buf_size); |
| if (rc == -1) { |
| LOGE("Work buffer allocation failure"); |
| return rc; |
| } else { |
| p_session->work_buffer = my_obj->ionBuffer[rc]; |
| } |
| } |
| } |
| |
| if (OMX_FALSE == p_session->active) { |
| LOGE("session not active %x", |
| job->encode_job.session_id); |
| return rc; |
| } |
| |
| if ((p_jobparams->src_index >= (int32_t)p_session->params.num_src_bufs) || |
| (p_jobparams->dst_index >= (int32_t)p_session->params.num_dst_bufs)) { |
| LOGE("invalid buffer indices"); |
| return rc; |
| } |
| |
| /* enqueue new job into todo job queue */ |
| node = (mm_jpeg_job_q_node_t *)malloc(sizeof(mm_jpeg_job_q_node_t)); |
| if (NULL == node) { |
| LOGE("No memory for mm_jpeg_job_q_node_t"); |
| return -1; |
| } |
| |
| KPI_ATRACE_INT("Camera:JPEG", |
| (int32_t)((uint32_t)session_idx<<16 | ++p_session->job_index)); |
| |
| *job_id = job->encode_job.session_id | |
| (((uint32_t)p_session->job_hist++ % JOB_HIST_MAX) << 16); |
| |
| memset(node, 0, sizeof(mm_jpeg_job_q_node_t)); |
| node->enc_info.encode_job = job->encode_job; |
| |
| #ifdef LIB2D_ROTATION_ENABLE |
| if (p_session->lib2d_rotation_flag) { |
| rc = mm_jpeg_lib2d_rotation(p_session, node, job, job_id); |
| if (rc < 0) { |
| LOGE("Lib2d rotation failed"); |
| return rc; |
| } |
| } |
| #endif |
| |
| if (p_session->thumb_from_main) { |
| node->enc_info.encode_job.thumb_dim.src_dim = |
| node->enc_info.encode_job.main_dim.src_dim; |
| node->enc_info.encode_job.thumb_dim.crop = |
| node->enc_info.encode_job.main_dim.crop; |
| if (p_session->lib2d_rotation_flag) { |
| if ((p_session->params.rotation == 90) || |
| (p_session->params.rotation == 270)) { |
| node->enc_info.encode_job.thumb_dim.dst_dim.width = |
| job->encode_job.thumb_dim.dst_dim.height; |
| node->enc_info.encode_job.thumb_dim.dst_dim.height = |
| job->encode_job.thumb_dim.dst_dim.width; |
| } |
| } |
| } |
| node->enc_info.job_id = *job_id; |
| node->enc_info.client_handle = p_session->client_hdl; |
| node->type = MM_JPEG_CMD_TYPE_JOB; |
| |
| qdata.p = node; |
| rc = mm_jpeg_queue_enq(&my_obj->job_mgr.job_queue, qdata); |
| if (0 == rc) { |
| cam_sem_post(&my_obj->job_mgr.job_sem); |
| } |
| |
| LOGH("session_idx %u client_idx %u job_id %d X", |
| session_idx, client_idx, *job_id); |
| |
| return rc; |
| } |
| |
| |
| |
| /** mm_jpeg_abort_job: |
| * |
| * Arguments: |
| * @my_obj: jpeg object |
| * @client_hdl: client handle |
| * @jobId: job id |
| * |
| * Return: |
| * 0 for success else failure |
| * |
| * Description: |
| * Abort the encoding session |
| * |
| **/ |
| int32_t mm_jpeg_abort_job(mm_jpeg_obj *my_obj, |
| uint32_t jobId) |
| { |
| int32_t rc = -1; |
| mm_jpeg_job_q_node_t *node = NULL; |
| mm_jpeg_job_session_t *p_session = NULL; |
| |
| pthread_mutex_lock(&my_obj->job_lock); |
| |
| /* abort job if in todo queue */ |
| node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->job_mgr.job_queue, jobId); |
| if (NULL != node) { |
| free(node); |
| goto abort_done; |
| } |
| |
| /* abort job if in ongoing queue */ |
| node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->ongoing_job_q, jobId); |
| if (NULL != node) { |
| /* find job that is OMX ongoing, ask OMX to abort the job */ |
| p_session = mm_jpeg_get_session(my_obj, node->enc_info.job_id); |
| if (p_session) { |
| mm_jpeg_session_abort(p_session); |
| } else { |
| LOGE("Invalid job id 0x%x", |
| node->enc_info.job_id); |
| } |
| free(node); |
| goto abort_done; |
| } |
| |
| abort_done: |
| pthread_mutex_unlock(&my_obj->job_lock); |
| |
| return rc; |
| } |
| |
| |
| #ifdef MM_JPEG_READ_META_KEYFILE |
| static int32_t mm_jpeg_read_meta_keyfile(mm_jpeg_job_session_t *p_session, |
| const char *filename) |
| { |
| int rc = 0; |
| FILE *fp = NULL; |
| size_t file_size = 0; |
| fp = fopen(filename, "r"); |
| if (!fp) { |
| LOGE("Key not present"); |
| return -1; |
| } |
| fseek(fp, 0, SEEK_END); |
| file_size = (size_t)ftell(fp); |
| fseek(fp, 0, SEEK_SET); |
| |
| p_session->meta_enc_key = (uint8_t *) malloc((file_size + 1) * sizeof(uint8_t)); |
| |
| if (!p_session->meta_enc_key) { |
| LOGE("error"); |
| return -1; |
| } |
| |
| fread(p_session->meta_enc_key, 1, file_size, fp); |
| fclose(fp); |
| |
| p_session->meta_enc_keylen = file_size; |
| |
| return rc; |
| } |
| #endif // MM_JPEG_READ_META_KEYFILE |
| |
| /** mm_jpeg_create_session: |
| * |
| * Arguments: |
| * @my_obj: jpeg object |
| * @client_hdl: client handle |
| * @p_params: pointer to encode params |
| * @p_session_id: session id |
| * |
| * Return: |
| * 0 for success else failure |
| * |
| * Description: |
| * Start the encoding session |
| * |
| **/ |
| int32_t mm_jpeg_create_session(mm_jpeg_obj *my_obj, |
| uint32_t client_hdl, |
| mm_jpeg_encode_params_t *p_params, |
| uint32_t* p_session_id) |
| { |
| mm_jpeg_q_data_t qdata; |
| int32_t rc = 0; |
| OMX_ERRORTYPE ret = OMX_ErrorNone; |
| uint8_t clnt_idx = 0; |
| int session_idx = -1; |
| mm_jpeg_job_session_t *p_session = NULL; |
| mm_jpeg_job_session_t * p_prev_session = NULL; |
| *p_session_id = 0; |
| uint32_t i = 0; |
| uint32_t j = 0; |
| uint32_t num_omx_sessions = 1; |
| uint32_t work_buf_size; |
| mm_jpeg_queue_t *p_session_handle_q, *p_out_buf_q; |
| uint32_t work_bufs_need; |
| char trace_tag[32]; |
| |
| /* validate the parameters */ |
| if ((p_params->num_src_bufs > MM_JPEG_MAX_BUF) |
| || (p_params->num_dst_bufs > MM_JPEG_MAX_BUF)) { |
| LOGE("invalid num buffers"); |
| return -1; |
| } |
| |
| /* check if valid client */ |
| clnt_idx = mm_jpeg_util_get_index_by_handler(client_hdl); |
| if (clnt_idx >= MAX_JPEG_CLIENT_NUM) { |
| LOGE("invalid client with handler (%d)", client_hdl); |
| return -1; |
| } |
| |
| if (p_params->burst_mode) { |
| num_omx_sessions = MM_JPEG_CONCURRENT_SESSIONS_COUNT; |
| } |
| |
| if (!my_obj->reuse_reproc_buffer) { |
| work_bufs_need = num_omx_sessions; |
| if (work_bufs_need > MM_JPEG_CONCURRENT_SESSIONS_COUNT) { |
| work_bufs_need = MM_JPEG_CONCURRENT_SESSIONS_COUNT; |
| } |
| LOGD(">>>> Work bufs need %d", work_bufs_need); |
| work_buf_size = CEILING64(my_obj->max_pic_w) * |
| CEILING64(my_obj->max_pic_h) * 3 / 2; |
| rc = mm_jpeg_alloc_workbuffer(my_obj, work_bufs_need, work_buf_size); |
| if (rc == -1) { |
| LOGE("Work buffer allocation failure"); |
| return rc; |
| } |
| } |
| |
| |
| /* init omx handle queue */ |
| p_session_handle_q = (mm_jpeg_queue_t *) malloc(sizeof(*p_session_handle_q)); |
| if (NULL == p_session_handle_q) { |
| LOGE("Error"); |
| goto error1; |
| } |
| rc = mm_jpeg_queue_init(p_session_handle_q); |
| if (0 != rc) { |
| LOGE("Error"); |
| free(p_session_handle_q); |
| goto error1; |
| } |
| |
| /* init output buf queue */ |
| p_out_buf_q = (mm_jpeg_queue_t *) malloc(sizeof(*p_out_buf_q)); |
| if (NULL == p_out_buf_q) { |
| LOGE("Error: Cannot allocate memory\n"); |
| return -1; |
| } |
| |
| /* init omx handle queue */ |
| rc = mm_jpeg_queue_init(p_out_buf_q); |
| if (0 != rc) { |
| LOGE("Error"); |
| free(p_out_buf_q); |
| goto error1; |
| } |
| |
| for (i = 0; i < num_omx_sessions; i++) { |
| uint32_t buf_idx = 0U; |
| session_idx = mm_jpeg_get_new_session_idx(my_obj, clnt_idx, &p_session); |
| if (session_idx < 0 || NULL == p_session) { |
| LOGE("invalid session id (%d)", session_idx); |
| goto error2; |
| } |
| |
| snprintf(trace_tag, sizeof(trace_tag), "Camera:JPEGsession%d", session_idx); |
| ATRACE_INT(trace_tag, 1); |
| |
| p_session->job_index = 0; |
| |
| p_session->next_session = NULL; |
| |
| if (p_prev_session) { |
| p_prev_session->next_session = p_session; |
| } |
| p_prev_session = p_session; |
| |
| buf_idx = i; |
| if (buf_idx < MM_JPEG_CONCURRENT_SESSIONS_COUNT) { |
| p_session->work_buffer = my_obj->ionBuffer[buf_idx]; |
| } else { |
| LOGE("Invalid Index, Setting buffer add to null"); |
| p_session->work_buffer.addr = NULL; |
| p_session->work_buffer.ion_fd = -1; |
| p_session->work_buffer.p_pmem_fd = -1; |
| } |
| |
| p_session->jpeg_obj = (void*)my_obj; /* save a ptr to jpeg_obj */ |
| |
| /*copy the params*/ |
| p_session->params = *p_params; |
| ret = mm_jpeg_session_create(p_session); |
| if (OMX_ErrorNone != ret) { |
| p_session->active = OMX_FALSE; |
| LOGE("jpeg session create failed"); |
| goto error2; |
| } |
| |
| uint32_t session_id = (JOB_ID_MAGICVAL << 24) | |
| ((uint32_t)session_idx << 8) | clnt_idx; |
| |
| if (!*p_session_id) { |
| *p_session_id = session_id; |
| } |
| |
| if (p_session->thumb_from_main) { |
| memcpy(p_session->params.src_thumb_buf, p_session->params.src_main_buf, |
| sizeof(p_session->params.src_thumb_buf)); |
| p_session->params.num_tmb_bufs = p_session->params.num_src_bufs; |
| if (!p_session->params.encode_thumbnail) { |
| p_session->params.num_tmb_bufs = 0; |
| } |
| p_session->params.thumb_dim.src_dim = p_session->params.main_dim.src_dim; |
| p_session->params.thumb_dim.crop = p_session->params.main_dim.crop; |
| } |
| #ifdef LIB2D_ROTATION_ENABLE |
| if (p_session->params.rotation) { |
| LOGD("Enable lib2d rotation"); |
| p_session->lib2d_rotation_flag = 1; |
| } else { |
| LOGD("Disable lib2d rotation"); |
| p_session->lib2d_rotation_flag = 0; |
| } |
| #else |
| p_session->lib2d_rotation_flag = 0; |
| #endif |
| |
| if (p_session->lib2d_rotation_flag) { |
| p_session->num_src_rot_bufs = p_session->params.num_src_bufs; |
| memset(p_session->src_rot_main_buf, 0, |
| sizeof(p_session->src_rot_main_buf)); |
| |
| for (j = 0; j < p_session->num_src_rot_bufs; j++) { |
| p_session->src_rot_main_buf[j].buf_size = |
| p_session->params.src_main_buf[j].buf_size; |
| p_session->src_rot_main_buf[j].format = |
| p_session->params.src_main_buf[j].format; |
| p_session->src_rot_main_buf[j].index = j; |
| |
| memset(&p_session->src_rot_ion_buffer[j], 0, sizeof(buffer_t)); |
| p_session->src_rot_ion_buffer[j].size = |
| p_session->src_rot_main_buf[j].buf_size; |
| p_session->src_rot_ion_buffer[j].addr = |
| (uint8_t *)buffer_allocate(&p_session->src_rot_ion_buffer[j], 1); |
| |
| if (NULL == p_session->src_rot_ion_buffer[j].addr) { |
| LOGE("Ion buff alloc for rotation failed"); |
| // deallocate all previously allocated rotation ion buffs |
| for (j = 0; j < p_session->num_src_rot_bufs; j++) { |
| if (p_session->src_rot_ion_buffer[j].addr) { |
| buffer_deallocate(&p_session->src_rot_ion_buffer[j]); |
| } |
| } |
| //fall back to SW encoding for rotation |
| p_session->lib2d_rotation_flag = 0; |
| } else { |
| p_session->src_rot_main_buf[j].buf_vaddr = |
| p_session->src_rot_ion_buffer[j].addr; |
| p_session->src_rot_main_buf[j].fd = |
| p_session->src_rot_ion_buffer[j].p_pmem_fd; |
| } |
| } |
| } |
| |
| p_session->client_hdl = client_hdl; |
| p_session->sessionId = session_id; |
| p_session->session_handle_q = p_session_handle_q; |
| p_session->out_buf_q = p_out_buf_q; |
| |
| qdata.p = p_session; |
| mm_jpeg_queue_enq(p_session_handle_q, qdata); |
| |
| p_session->meta_enc_key = NULL; |
| p_session->meta_enc_keylen = 0; |
| |
| #ifdef MM_JPEG_READ_META_KEYFILE |
| mm_jpeg_read_meta_keyfile(p_session, META_KEYFILE); |
| #endif |
| |
| pthread_mutex_lock(&my_obj->job_lock); |
| /* Configure session if not already configured and if |
| no other session configured*/ |
| if ((OMX_FALSE == p_session->config) && |
| (my_obj->p_session_inprogress == NULL)) { |
| rc = mm_jpeg_session_configure(p_session); |
| if (rc) { |
| LOGE("Error"); |
| pthread_mutex_unlock(&my_obj->job_lock); |
| goto error2; |
| } |
| p_session->config = OMX_TRUE; |
| my_obj->p_session_inprogress = p_session; |
| } |
| pthread_mutex_unlock(&my_obj->job_lock); |
| p_session->num_omx_sessions = num_omx_sessions; |
| |
| LOGH("session id %x thumb_from_main %d", |
| session_id, p_session->thumb_from_main); |
| } |
| |
| // Queue the output buf indexes |
| for (i = 0; i < p_params->num_dst_bufs; i++) { |
| qdata.u32 = i + 1; |
| mm_jpeg_queue_enq(p_out_buf_q, qdata); |
| } |
| |
| return rc; |
| |
| error1: |
| rc = -1; |
| error2: |
| if (NULL != p_session) { |
| ATRACE_INT(trace_tag, 0); |
| } |
| return rc; |
| } |
| |
| /** mm_jpegenc_destroy_job |
| * |
| * Arguments: |
| * @p_session: Session obj |
| * |
| * Return: |
| * 0 for success else failure |
| * |
| * Description: |
| * Destroy the job based paramenters |
| * |
| **/ |
| static int32_t mm_jpegenc_destroy_job(mm_jpeg_job_session_t *p_session) |
| { |
| mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job; |
| int i = 0, rc = 0; |
| |
| LOGD("Exif entry count %d %d", |
| (int)p_jobparams->exif_info.numOfEntries, |
| (int)p_session->exif_count_local); |
| for (i = 0; i < p_session->exif_count_local; i++) { |
| rc = releaseExifEntry(&p_session->exif_info_local[i]); |
| if (rc) { |
| LOGE("Exif release failed (%d)", rc); |
| } |
| } |
| p_session->exif_count_local = 0; |
| |
| return rc; |
| } |
| |
| /** mm_jpeg_session_encode: |
| * |
| * Arguments: |
| * @p_session: encode session |
| * |
| * Return: |
| * OMX_ERRORTYPE |
| * |
| * Description: |
| * Start the encoding |
| * |
| **/ |
| static void mm_jpegenc_job_done(mm_jpeg_job_session_t *p_session) |
| { |
| mm_jpeg_q_data_t qdata; |
| mm_jpeg_obj *my_obj = (mm_jpeg_obj *)p_session->jpeg_obj; |
| mm_jpeg_job_q_node_t *node = NULL; |
| |
| /*Destroy job related params*/ |
| mm_jpegenc_destroy_job(p_session); |
| |
| /*remove the job*/ |
| node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->ongoing_job_q, |
| p_session->jobId); |
| if (node) { |
| free(node); |
| } |
| p_session->encoding = OMX_FALSE; |
| |
| // Queue to available sessions |
| qdata.p = p_session; |
| mm_jpeg_queue_enq(p_session->session_handle_q, qdata); |
| |
| if (p_session->auto_out_buf) { |
| //Queue out buf index |
| qdata.u32 = (uint32_t)(p_session->encode_job.dst_index + 1); |
| mm_jpeg_queue_enq(p_session->out_buf_q, qdata); |
| } |
| |
| /* wake up jobMgr thread to work on new job if there is any */ |
| cam_sem_post(&my_obj->job_mgr.job_sem); |
| } |
| |
| /** mm_jpeg_destroy_session: |
| * |
| * Arguments: |
| * @my_obj: jpeg object |
| * @session_id: session index |
| * |
| * Return: |
| * 0 for success else failure |
| * |
| * Description: |
| * Destroy the encoding session |
| * |
| **/ |
| int32_t mm_jpeg_destroy_session(mm_jpeg_obj *my_obj, |
| mm_jpeg_job_session_t *p_session) |
| { |
| mm_jpeg_q_data_t qdata; |
| int32_t rc = 0; |
| mm_jpeg_job_q_node_t *node = NULL; |
| uint32_t session_id = 0; |
| mm_jpeg_job_session_t *p_cur_sess; |
| char trace_tag[32]; |
| |
| if (NULL == p_session) { |
| LOGE("invalid session"); |
| return rc; |
| } |
| |
| session_id = p_session->sessionId; |
| |
| pthread_mutex_lock(&my_obj->job_lock); |
| |
| /* abort job if in todo queue */ |
| LOGD("abort todo jobs"); |
| node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id); |
| while (NULL != node) { |
| free(node); |
| node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id); |
| } |
| |
| /* abort job if in ongoing queue */ |
| LOGD("abort ongoing jobs"); |
| node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id); |
| while (NULL != node) { |
| free(node); |
| node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id); |
| } |
| |
| /* abort the current session */ |
| mm_jpeg_session_abort(p_session); |
| mm_jpeg_session_destroy(p_session); |
| |
| p_cur_sess = p_session; |
| |
| do { |
| mm_jpeg_remove_session_idx(my_obj, p_cur_sess->sessionId); |
| } while (NULL != (p_cur_sess = p_cur_sess->next_session)); |
| |
| |
| pthread_mutex_unlock(&my_obj->job_lock); |
| |
| while (1) { |
| qdata = mm_jpeg_queue_deq(p_session->session_handle_q); |
| if (NULL == qdata.p) |
| break; |
| } |
| mm_jpeg_queue_deinit(p_session->session_handle_q); |
| free(p_session->session_handle_q); |
| p_session->session_handle_q = NULL; |
| |
| while (1) { |
| qdata = mm_jpeg_queue_deq(p_session->out_buf_q); |
| if (0U == qdata.u32) |
| break; |
| } |
| mm_jpeg_queue_deinit(p_session->out_buf_q); |
| free(p_session->out_buf_q); |
| p_session->out_buf_q = NULL; |
| |
| |
| /* wake up jobMgr thread to work on new job if there is any */ |
| cam_sem_post(&my_obj->job_mgr.job_sem); |
| |
| snprintf(trace_tag, sizeof(trace_tag), "Camera:JPEGsession%d", GET_SESSION_IDX(session_id)); |
| ATRACE_INT(trace_tag, 0); |
| |
| LOGH("destroy session successful. X"); |
| |
| return rc; |
| } |
| |
| |
| |
| |
| /** mm_jpeg_destroy_session: |
| * |
| * Arguments: |
| * @my_obj: jpeg object |
| * @session_id: session index |
| * |
| * Return: |
| * 0 for success else failure |
| * |
| * Description: |
| * Destroy the encoding session |
| * |
| **/ |
| int32_t mm_jpeg_destroy_session_unlocked(mm_jpeg_obj *my_obj, |
| mm_jpeg_job_session_t *p_session) |
| { |
| int32_t rc = -1; |
| mm_jpeg_job_q_node_t *node = NULL; |
| uint32_t session_id = 0; |
| if (NULL == p_session) { |
| LOGE("invalid session"); |
| return rc; |
| } |
| |
| session_id = p_session->sessionId; |
| |
| /* abort job if in todo queue */ |
| LOGD("abort todo jobs"); |
| node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id); |
| while (NULL != node) { |
| free(node); |
| node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id); |
| } |
| |
| /* abort job if in ongoing queue */ |
| LOGD("abort ongoing jobs"); |
| node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id); |
| while (NULL != node) { |
| free(node); |
| node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id); |
| } |
| |
| /* abort the current session */ |
| mm_jpeg_session_abort(p_session); |
| //mm_jpeg_remove_session_idx(my_obj, session_id); |
| |
| return rc; |
| } |
| |
| /** mm_jpeg_destroy_session: |
| * |
| * Arguments: |
| * @my_obj: jpeg object |
| * @session_id: session index |
| * |
| * Return: |
| * 0 for success else failure |
| * |
| * Description: |
| * Destroy the encoding session |
| * |
| **/ |
| int32_t mm_jpeg_destroy_session_by_id(mm_jpeg_obj *my_obj, uint32_t session_id) |
| { |
| mm_jpeg_job_session_t *p_session = mm_jpeg_get_session(my_obj, session_id); |
| |
| return mm_jpeg_destroy_session(my_obj, p_session); |
| } |
| |
| |
| |
| /** mm_jpeg_close: |
| * |
| * Arguments: |
| * @my_obj: jpeg object |
| * @client_hdl: client handle |
| * |
| * Return: |
| * 0 for success else failure |
| * |
| * Description: |
| * Close the jpeg client |
| * |
| **/ |
| int32_t mm_jpeg_close(mm_jpeg_obj *my_obj, uint32_t client_hdl) |
| { |
| int32_t rc = -1; |
| uint8_t clnt_idx = 0; |
| int i = 0; |
| |
| /* check if valid client */ |
| clnt_idx = mm_jpeg_util_get_index_by_handler(client_hdl); |
| if (clnt_idx >= MAX_JPEG_CLIENT_NUM) { |
| LOGE("invalid client with handler (%d)", client_hdl); |
| return rc; |
| } |
| |
| LOGD("E"); |
| |
| /* abort all jobs from the client */ |
| pthread_mutex_lock(&my_obj->job_lock); |
| |
| for (i = 0; i < MM_JPEG_MAX_SESSION; i++) { |
| if (OMX_TRUE == my_obj->clnt_mgr[clnt_idx].session[i].active) |
| mm_jpeg_destroy_session_unlocked(my_obj, |
| &my_obj->clnt_mgr[clnt_idx].session[i]); |
| } |
| |
| #ifdef LOAD_ADSP_RPC_LIB |
| if (NULL != my_obj->adsprpc_lib_handle) { |
| dlclose(my_obj->adsprpc_lib_handle); |
| my_obj->adsprpc_lib_handle = NULL; |
| } |
| #endif |
| |
| pthread_mutex_unlock(&my_obj->job_lock); |
| |
| /* invalidate client session */ |
| pthread_mutex_destroy(&my_obj->clnt_mgr[clnt_idx].lock); |
| memset(&my_obj->clnt_mgr[clnt_idx], 0, sizeof(mm_jpeg_client_t)); |
| |
| rc = 0; |
| LOGD("X"); |
| return rc; |
| } |
| |
| OMX_ERRORTYPE mm_jpeg_ebd(OMX_HANDLETYPE hComponent, |
| OMX_PTR pAppData, |
| OMX_BUFFERHEADERTYPE *pBuffer) |
| { |
| mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData; |
| |
| LOGH("count %d ", p_session->ebd_count); |
| pthread_mutex_lock(&p_session->lock); |
| p_session->ebd_count++; |
| pthread_mutex_unlock(&p_session->lock); |
| return 0; |
| } |
| |
| OMX_ERRORTYPE mm_jpeg_fbd(OMX_HANDLETYPE hComponent, |
| OMX_PTR pAppData, |
| OMX_BUFFERHEADERTYPE *pBuffer) |
| { |
| OMX_ERRORTYPE ret = OMX_ErrorNone; |
| mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData; |
| mm_jpeg_output_t output_buf; |
| LOGI("count %d ", p_session->fbd_count); |
| LOGI("KPI Perf] : PROFILE_JPEG_FBD"); |
| |
| pthread_mutex_lock(&p_session->lock); |
| KPI_ATRACE_INT("Camera:JPEG", |
| (int32_t)((uint32_t)GET_SESSION_IDX( |
| p_session->sessionId)<<16 | --p_session->job_index)); |
| if (MM_JPEG_ABORT_NONE != p_session->abort_state) { |
| pthread_mutex_unlock(&p_session->lock); |
| return ret; |
| } |
| #ifdef MM_JPEG_DUMP_OUT_BS |
| char filename[256]; |
| static int bsc; |
| snprintf(filename, sizeof(filename), |
| QCAMERA_DUMP_FRM_LOCATION"jpeg/mm_jpeg_bs%d.jpg", bsc++); |
| DUMP_TO_FILE(filename, |
| pBuffer->pBuffer, |
| (size_t)(uint32_t)pBuffer->nFilledLen); |
| #endif |
| |
| p_session->fbd_count++; |
| if (NULL != p_session->params.jpeg_cb) { |
| |
| p_session->job_status = JPEG_JOB_STATUS_DONE; |
| output_buf.buf_filled_len = (uint32_t)pBuffer->nFilledLen; |
| output_buf.buf_vaddr = pBuffer->pBuffer; |
| output_buf.fd = -1; |
| LOGH("send jpeg callback %d buf 0x%p len %u JobID %u", |
| p_session->job_status, pBuffer->pBuffer, |
| (unsigned int)pBuffer->nFilledLen, p_session->jobId); |
| p_session->params.jpeg_cb(p_session->job_status, |
| p_session->client_hdl, |
| p_session->jobId, |
| &output_buf, |
| p_session->params.userdata); |
| |
| mm_jpegenc_job_done(p_session); |
| |
| mm_jpeg_put_mem((void *)p_session); |
| } |
| pthread_mutex_unlock(&p_session->lock); |
| |
| return ret; |
| } |
| |
| |
| |
| OMX_ERRORTYPE mm_jpeg_event_handler(OMX_HANDLETYPE hComponent, |
| OMX_PTR pAppData, |
| OMX_EVENTTYPE eEvent, |
| OMX_U32 nData1, |
| OMX_U32 nData2, |
| OMX_PTR pEventData) |
| { |
| mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData; |
| |
| LOGD("%d %d %d state %d", eEvent, (int)nData1, |
| (int)nData2, p_session->abort_state); |
| |
| pthread_mutex_lock(&p_session->lock); |
| |
| if (MM_JPEG_ABORT_INIT == p_session->abort_state) { |
| p_session->abort_state = MM_JPEG_ABORT_DONE; |
| pthread_cond_signal(&p_session->cond); |
| pthread_mutex_unlock(&p_session->lock); |
| return OMX_ErrorNone; |
| } |
| |
| if (eEvent == OMX_EventError) { |
| p_session->error_flag = nData2; |
| if (p_session->encoding == OMX_TRUE) { |
| LOGE("Error during encoding"); |
| |
| /* send jpeg callback */ |
| if (NULL != p_session->params.jpeg_cb) { |
| p_session->job_status = JPEG_JOB_STATUS_ERROR; |
| LOGE("send jpeg error callback %d", |
| p_session->job_status); |
| p_session->params.jpeg_cb(p_session->job_status, |
| p_session->client_hdl, |
| p_session->jobId, |
| NULL, |
| p_session->params.userdata); |
| } |
| |
| /* remove from ready queue */ |
| mm_jpegenc_job_done(p_session); |
| } |
| pthread_cond_signal(&p_session->cond); |
| } else if (eEvent == OMX_EventCmdComplete) { |
| if (p_session->state_change_pending == OMX_TRUE) { |
| p_session->state_change_pending = OMX_FALSE; |
| pthread_cond_signal(&p_session->cond); |
| } |
| } |
| |
| pthread_mutex_unlock(&p_session->lock); |
| return OMX_ErrorNone; |
| } |
| |
| |
| |
| /* remove the first job from the queue with matching client handle */ |
| mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_client_id( |
| mm_jpeg_queue_t* queue, uint32_t client_hdl) |
| { |
| mm_jpeg_q_node_t* node = NULL; |
| mm_jpeg_job_q_node_t* data = NULL; |
| mm_jpeg_job_q_node_t* job_node = NULL; |
| struct cam_list *head = NULL; |
| struct cam_list *pos = NULL; |
| |
| pthread_mutex_lock(&queue->lock); |
| head = &queue->head.list; |
| pos = head->next; |
| while(pos != head) { |
| node = member_of(pos, mm_jpeg_q_node_t, list); |
| data = (mm_jpeg_job_q_node_t *)node->data.p; |
| |
| if (data && (data->enc_info.client_handle == client_hdl)) { |
| LOGH("found matching client handle"); |
| job_node = data; |
| cam_list_del_node(&node->list); |
| queue->size--; |
| free(node); |
| LOGH("queue size = %d", queue->size); |
| break; |
| } |
| pos = pos->next; |
| } |
| |
| pthread_mutex_unlock(&queue->lock); |
| |
| return job_node; |
| } |
| |
| /* remove the first job from the queue with matching session id */ |
| mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_session_id( |
| mm_jpeg_queue_t* queue, uint32_t session_id) |
| { |
| mm_jpeg_q_node_t* node = NULL; |
| mm_jpeg_job_q_node_t* data = NULL; |
| mm_jpeg_job_q_node_t* job_node = NULL; |
| struct cam_list *head = NULL; |
| struct cam_list *pos = NULL; |
| |
| pthread_mutex_lock(&queue->lock); |
| head = &queue->head.list; |
| pos = head->next; |
| while(pos != head) { |
| node = member_of(pos, mm_jpeg_q_node_t, list); |
| data = (mm_jpeg_job_q_node_t *)node->data.p; |
| |
| if (data && (data->enc_info.encode_job.session_id == session_id)) { |
| LOGH("found matching session id"); |
| job_node = data; |
| cam_list_del_node(&node->list); |
| queue->size--; |
| free(node); |
| LOGH("queue size = %d", queue->size); |
| break; |
| } |
| pos = pos->next; |
| } |
| |
| pthread_mutex_unlock(&queue->lock); |
| |
| return job_node; |
| } |
| |
| /* remove job from the queue with matching job id */ |
| mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_job_id( |
| mm_jpeg_queue_t* queue, uint32_t job_id) |
| { |
| mm_jpeg_q_node_t* node = NULL; |
| mm_jpeg_job_q_node_t* data = NULL; |
| mm_jpeg_job_q_node_t* job_node = NULL; |
| struct cam_list *head = NULL; |
| struct cam_list *pos = NULL; |
| uint32_t lq_job_id; |
| |
| pthread_mutex_lock(&queue->lock); |
| head = &queue->head.list; |
| pos = head->next; |
| while(pos != head) { |
| node = member_of(pos, mm_jpeg_q_node_t, list); |
| data = (mm_jpeg_job_q_node_t *)node->data.p; |
| |
| if(NULL == data) { |
| LOGE("Data is NULL"); |
| pthread_mutex_unlock(&queue->lock); |
| return NULL; |
| } |
| |
| if (data->type == MM_JPEG_CMD_TYPE_DECODE_JOB) { |
| lq_job_id = data->dec_info.job_id; |
| } else { |
| lq_job_id = data->enc_info.job_id; |
| } |
| |
| if (data && (lq_job_id == job_id)) { |
| LOGD("found matching job id"); |
| job_node = data; |
| cam_list_del_node(&node->list); |
| queue->size--; |
| free(node); |
| break; |
| } |
| pos = pos->next; |
| } |
| |
| pthread_mutex_unlock(&queue->lock); |
| |
| return job_node; |
| } |
| |
| /* remove job from the queue with matching job id */ |
| mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_unlk( |
| mm_jpeg_queue_t* queue, uint32_t job_id) |
| { |
| mm_jpeg_q_node_t* node = NULL; |
| mm_jpeg_job_q_node_t* data = NULL; |
| mm_jpeg_job_q_node_t* job_node = NULL; |
| struct cam_list *head = NULL; |
| struct cam_list *pos = NULL; |
| |
| head = &queue->head.list; |
| pos = head->next; |
| while(pos != head) { |
| node = member_of(pos, mm_jpeg_q_node_t, list); |
| data = (mm_jpeg_job_q_node_t *)node->data.p; |
| |
| if (data && (data->enc_info.job_id == job_id)) { |
| job_node = data; |
| cam_list_del_node(&node->list); |
| queue->size--; |
| free(node); |
| break; |
| } |
| pos = pos->next; |
| } |
| |
| return job_node; |
| } |