/* Copyright (c) 2013-2014, 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.
*
*/
#include <pthread.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <poll.h>
#include "mm_jpeg_dbg.h"
#include "mm_jpeg_interface.h"
#include "mm_jpeg.h"
#include "mm_jpeg_inlines.h"
OMX_ERRORTYPE mm_jpegdec_ebd(OMX_HANDLETYPE hComponent,
OMX_PTR pAppData,
OMX_BUFFERHEADERTYPE *pBuffer);
OMX_ERRORTYPE mm_jpegdec_fbd(OMX_HANDLETYPE hComponent,
OMX_PTR pAppData,
OMX_BUFFERHEADERTYPE* pBuffer);
OMX_ERRORTYPE mm_jpegdec_event_handler(OMX_HANDLETYPE hComponent,
OMX_PTR pAppData,
OMX_EVENTTYPE eEvent,
OMX_U32 nData1,
OMX_U32 nData2,
OMX_PTR pEventData);
/** mm_jpegdec_destroy_job
*
* Arguments:
* @p_session: Session obj
*
* Return:
* 0 for success else failure
*
* Description:
* Destroy the job based paramenters
*
**/
static int32_t mm_jpegdec_destroy_job(mm_jpeg_job_session_t *p_session)
{
int32_t rc = 0;
return rc;
}
/** mm_jpeg_job_done:
*
* Arguments:
* @p_session: decode session
*
* Return:
* OMX_ERRORTYPE
*
* Description:
* Finalize the job
*
**/
static void mm_jpegdec_job_done(mm_jpeg_job_session_t *p_session)
{
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_jpegdec_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;
/* wake up jobMgr thread to work on new job if there is any */
cam_sem_post(&my_obj->job_mgr.job_sem);
}
/** mm_jpegdec_session_send_buffers:
*
* Arguments:
* @data: job session
*
* Return:
* OMX error values
*
* Description:
* Send the buffers to OMX layer
*
**/
OMX_ERRORTYPE mm_jpegdec_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_decode_params_t *p_params = &p_session->dec_params;
memset(&lbuffer_info, 0x0, sizeof(QOMX_BUFFER_INFO));
for (i = 0; i < p_params->num_src_bufs; i++) {
CDBG("%s:%d] Source buffer %d", __func__, __LINE__, 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) {
CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
return ret;
}
}
CDBG("%s:%d]", __func__, __LINE__);
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_jpegdec_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_decode_params_t *p_params = &p_session->dec_params;
for (i = 0; i < p_params->num_src_bufs; i++) {
CDBG("%s:%d] Source buffer %d", __func__, __LINE__, i);
ret = OMX_FreeBuffer(p_session->omx_handle, 0, p_session->p_in_omx_buf[i]);
if (ret) {
CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
return ret;
}
}
for (i = 0; i < p_params->num_dst_bufs; i++) {
CDBG("%s:%d] Dest buffer %d", __func__, __LINE__, i);
ret = OMX_FreeBuffer(p_session->omx_handle, 1, p_session->p_out_omx_buf[i]);
if (ret) {
CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
return ret;
}
}
CDBG("%s:%d]", __func__, __LINE__);
return ret;
}
/** mm_jpegdec_session_create:
*
* Arguments:
* @p_session: job session
*
* Return:
* OMX error types
*
* Description:
* Create a jpeg encode session
*
**/
OMX_ERRORTYPE mm_jpegdec_session_create(mm_jpeg_job_session_t* p_session)
{
OMX_ERRORTYPE rc = OMX_ErrorNone;
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->omx_callbacks.EmptyBufferDone = mm_jpegdec_ebd;
p_session->omx_callbacks.FillBufferDone = mm_jpegdec_fbd;
p_session->omx_callbacks.EventHandler = mm_jpegdec_event_handler;
p_session->exif_count_local = 0;
rc = OMX_GetHandle(&p_session->omx_handle,
"OMX.qcom.image.jpeg.decoder",
(void *)p_session,
&p_session->omx_callbacks);
if (OMX_ErrorNone != rc) {
CDBG_ERROR("%s:%d] OMX_GetHandle failed (%d)", __func__, __LINE__, rc);
return rc;
}
return rc;
}
/** mm_jpegdec_session_destroy:
*
* Arguments:
* @p_session: job session
*
* Return:
* none
*
* Description:
* Destroy a jpeg encode session
*
**/
void mm_jpegdec_session_destroy(mm_jpeg_job_session_t* p_session)
{
OMX_ERRORTYPE rc = OMX_ErrorNone;
CDBG("%s:%d] E", __func__, __LINE__);
if (NULL == p_session->omx_handle) {
CDBG_ERROR("%s:%d] invalid handle", __func__, __LINE__);
return;
}
rc = mm_jpeg_session_change_state(p_session, OMX_StateIdle, NULL);
if (rc) {
CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
}
rc = mm_jpeg_session_change_state(p_session, OMX_StateLoaded,
mm_jpegdec_session_free_buffers);
if (rc) {
CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
}
rc = OMX_FreeHandle(p_session->omx_handle);
if (0 != rc) {
CDBG_ERROR("%s:%d] OMX_FreeHandle failed (%d)", __func__, __LINE__, rc);
}
p_session->omx_handle = NULL;
pthread_mutex_destroy(&p_session->lock);
pthread_cond_destroy(&p_session->cond);
CDBG("%s:%d] X", __func__, __LINE__);
}
/** mm_jpeg_session_config_port:
*
* Arguments:
* @p_session: job session
*
* Return:
* OMX error values
*
* Description:
* Configure OMX ports
*
**/
OMX_ERRORTYPE mm_jpegdec_session_config_ports(mm_jpeg_job_session_t* p_session)
{
OMX_ERRORTYPE ret = OMX_ErrorNone;
mm_jpeg_decode_params_t *p_params = &p_session->dec_params;
mm_jpeg_decode_job_t *p_jobparams = &p_session->decode_job;
mm_jpeg_buf_t *p_src_buf =
&p_params->src_main_buf[p_jobparams->src_index];
p_session->inputPort.nPortIndex = 0;
p_session->outputPort.nPortIndex = 1;
ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
&p_session->inputPort);
if (ret) {
CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
return ret;
}
ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
&p_session->outputPort);
if (ret) {
CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
return ret;
}
p_session->inputPort.format.image.nFrameWidth =
(OMX_U32)p_jobparams->main_dim.src_dim.width;
p_session->inputPort.format.image.nFrameHeight =
(OMX_U32)p_jobparams->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[p_jobparams->src_index].buf_size;
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) {
CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
return ret;
}
return ret;
}
/** mm_jpegdec_session_config_main:
*
* Arguments:
* @p_session: job session
*
* Return:
* OMX error values
*
* Description:
* Configure main image
*
**/
OMX_ERRORTYPE mm_jpegdec_session_config_main(mm_jpeg_job_session_t *p_session)
{
OMX_ERRORTYPE rc = OMX_ErrorNone;
/* config port */
CDBG("%s:%d] config port", __func__, __LINE__);
rc = mm_jpegdec_session_config_ports(p_session);
if (OMX_ErrorNone != rc) {
CDBG_ERROR("%s: config port failed", __func__);
return rc;
}
/* TODO: config crop */
return rc;
}
/** mm_jpeg_session_configure:
*
* Arguments:
* @data: encode session
*
* Return:
* none
*
* Description:
* Configure the session
*
**/
static OMX_ERRORTYPE mm_jpegdec_session_configure(mm_jpeg_job_session_t *p_session)
{
OMX_ERRORTYPE ret = OMX_ErrorNone;
CDBG("%s:%d] E ", __func__, __LINE__);
MM_JPEG_CHK_ABORT(p_session, ret, error);
/* config main img */
ret = mm_jpegdec_session_config_main(p_session);
if (OMX_ErrorNone != ret) {
CDBG_ERROR("%s:%d] config main img failed", __func__, __LINE__);
goto error;
}
/* TODO: common config (if needed) */
ret = mm_jpeg_session_change_state(p_session, OMX_StateIdle,
mm_jpegdec_session_send_buffers);
if (ret) {
CDBG_ERROR("%s:%d] change state to idle failed %d",
__func__, __LINE__, ret);
goto error;
}
ret = mm_jpeg_session_change_state(p_session, OMX_StateExecuting,
NULL);
if (ret) {
CDBG_ERROR("%s:%d] change state to executing failed %d",
__func__, __LINE__, ret);
goto error;
}
error:
CDBG("%s:%d] X ret %d", __func__, __LINE__, ret);
return ret;
}
static OMX_ERRORTYPE mm_jpeg_session_port_enable(
mm_jpeg_job_session_t *p_session,
OMX_U32 nPortIndex,
OMX_BOOL wait)
{
OMX_ERRORTYPE ret = OMX_ErrorNone;
OMX_EVENTTYPE lEvent;
pthread_mutex_lock(&p_session->lock);
p_session->event_pending = OMX_TRUE;
pthread_mutex_unlock(&p_session->lock);
ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortEnable,
nPortIndex, NULL);
if (ret) {
CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
return ret;
}
if (wait == OMX_TRUE) {
// Wait for cmd complete
pthread_mutex_lock(&p_session->lock);
if (p_session->event_pending == OMX_TRUE) {
CDBG("%s:%d] before wait", __func__, __LINE__);
pthread_cond_wait(&p_session->cond, &p_session->lock);
lEvent = p_session->omxEvent;
CDBG("%s:%d] after wait", __func__, __LINE__);
}
lEvent = p_session->omxEvent;
pthread_mutex_unlock(&p_session->lock);
if (lEvent != OMX_EventCmdComplete) {
CDBG("%s:%d] Unexpected event %d", __func__, __LINE__,lEvent);
return OMX_ErrorUndefined;
}
}
return OMX_ErrorNone;
}
static OMX_ERRORTYPE mm_jpeg_session_port_disable(
mm_jpeg_job_session_t *p_session,
OMX_U32 nPortIndex,
OMX_BOOL wait)
{
OMX_ERRORTYPE ret = OMX_ErrorNone;
OMX_EVENTTYPE lEvent;
pthread_mutex_lock(&p_session->lock);
p_session->event_pending = OMX_TRUE;
pthread_mutex_unlock(&p_session->lock);
ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortDisable,
nPortIndex, NULL);
if (ret) {
CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
return ret;
}
if (wait == OMX_TRUE) {
// Wait for cmd complete
pthread_mutex_lock(&p_session->lock);
if (p_session->event_pending == OMX_TRUE) {
CDBG("%s:%d] before wait", __func__, __LINE__);
pthread_cond_wait(&p_session->cond, &p_session->lock);
CDBG("%s:%d] after wait", __func__, __LINE__);
}
lEvent = p_session->omxEvent;
pthread_mutex_unlock(&p_session->lock);
if (lEvent != OMX_EventCmdComplete) {
CDBG("%s:%d] Unexpected event %d", __func__, __LINE__,lEvent);
return OMX_ErrorUndefined;
}
}
return OMX_ErrorNone;
}
/** mm_jpegdec_session_decode:
*
* Arguments:
* @p_session: encode session
*
* Return:
* OMX_ERRORTYPE
*
* Description:
* Start the encoding
*
**/
static OMX_ERRORTYPE mm_jpegdec_session_decode(mm_jpeg_job_session_t *p_session)
{
OMX_ERRORTYPE ret = OMX_ErrorNone;
mm_jpeg_decode_params_t *p_params = &p_session->dec_params;
mm_jpeg_decode_job_t *p_jobparams = &p_session->decode_job;
OMX_EVENTTYPE lEvent;
uint32_t i;
QOMX_BUFFER_INFO lbuffer_info;
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 (OMX_FALSE == p_session->config) {
ret = mm_jpegdec_session_configure(p_session);
if (ret) {
CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
goto error;
}
p_session->config = OMX_TRUE;
}
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);
p_session->event_pending = OMX_TRUE;
ret = OMX_EmptyThisBuffer(p_session->omx_handle,
p_session->p_in_omx_buf[p_jobparams->src_index]);
if (ret) {
CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
goto error;
}
// Wait for port settings changed
pthread_mutex_lock(&p_session->lock);
if (p_session->event_pending == OMX_TRUE) {
CDBG("%s:%d] before wait", __func__, __LINE__);
pthread_cond_wait(&p_session->cond, &p_session->lock);
}
lEvent = p_session->omxEvent;
CDBG("%s:%d] after wait", __func__, __LINE__);
pthread_mutex_unlock(&p_session->lock);
if (lEvent != OMX_EventPortSettingsChanged) {
CDBG("%s:%d] Unexpected event %d", __func__, __LINE__,lEvent);
goto error;
}
// Disable output port (wait)
mm_jpeg_session_port_disable(p_session,
p_session->outputPort.nPortIndex,
OMX_TRUE);
// Get port definition
ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
&p_session->outputPort);
if (ret) {
CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
return ret;
}
// Set port definition
p_session->outputPort.format.image.nFrameWidth =
(OMX_U32)p_jobparams->main_dim.dst_dim.width;
p_session->outputPort.format.image.nFrameHeight =
(OMX_U32)p_jobparams->main_dim.dst_dim.height;
p_session->outputPort.format.image.eColorFormat =
map_jpeg_format(p_params->color_format);
p_session->outputPort.nBufferSize =
p_params->dest_buf[p_jobparams->dst_index].buf_size;
p_session->outputPort.nBufferCountActual = (OMX_U32)p_params->num_dst_bufs;
p_session->outputPort.format.image.nSliceHeight =
(OMX_U32)
p_params->dest_buf[p_jobparams->dst_index].offset.mp[0].scanline;
p_session->outputPort.format.image.nStride =
p_params->dest_buf[p_jobparams->dst_index].offset.mp[0].stride;
ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
&p_session->outputPort);
if (ret) {
CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
return ret;
}
// Enable port (no wait)
mm_jpeg_session_port_enable(p_session,
p_session->outputPort.nPortIndex,
OMX_FALSE);
memset(&lbuffer_info, 0x0, sizeof(QOMX_BUFFER_INFO));
// Use buffers
for (i = 0; i < p_params->num_dst_bufs; i++) {
lbuffer_info.fd = (OMX_U32)p_params->dest_buf[i].fd;
CDBG("%s:%d] Dest buffer %d", __func__, __LINE__, (unsigned int)i);
ret = OMX_UseBuffer(p_session->omx_handle, &(p_session->p_out_omx_buf[i]),
1, &lbuffer_info, p_params->dest_buf[i].buf_size,
p_params->dest_buf[i].buf_vaddr);
if (ret) {
CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
return ret;
}
}
// Wait for port enable completion
pthread_mutex_lock(&p_session->lock);
if (p_session->event_pending == OMX_TRUE) {
CDBG("%s:%d] before wait", __func__, __LINE__);
pthread_cond_wait(&p_session->cond, &p_session->lock);
lEvent = p_session->omxEvent;
CDBG("%s:%d] after wait", __func__, __LINE__);
}
lEvent = p_session->omxEvent;
pthread_mutex_unlock(&p_session->lock);
if (lEvent != OMX_EventCmdComplete) {
CDBG("%s:%d] Unexpected event %d", __func__, __LINE__,lEvent);
goto error;
}
ret = OMX_FillThisBuffer(p_session->omx_handle,
p_session->p_out_omx_buf[p_jobparams->dst_index]);
if (ret) {
CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
goto error;
}
MM_JPEG_CHK_ABORT(p_session, ret, error);
error:
CDBG("%s:%d] X ", __func__, __LINE__);
return ret;
}
/** mm_jpegdec_process_decoding_job:
*
* Arguments:
* @my_obj: jpeg client
* @job_node: job node
*
* Return:
* 0 for success -1 otherwise
*
* Description:
* Start the encoding job
*
**/
int32_t mm_jpegdec_process_decoding_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;
/* check if valid session */
p_session = mm_jpeg_get_session(my_obj, job_node->dec_info.job_id);
if (NULL == p_session) {
CDBG_ERROR("%s:%d] invalid job id %x", __func__, __LINE__,
job_node->dec_info.job_id);
return -1;
}
/* 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) {
CDBG_ERROR("%s:%d] jpeg enqueue failed %d",
__func__, __LINE__, ret);
goto error;
}
p_session->decode_job = job_node->dec_info.decode_job;
p_session->jobId = job_node->dec_info.job_id;
ret = mm_jpegdec_session_decode(p_session);
if (ret) {
CDBG_ERROR("%s:%d] encode session failed", __func__, __LINE__);
goto error;
}
CDBG("%s:%d] Success X ", __func__, __LINE__);
return rc;
error:
if ((OMX_ErrorNone != ret) &&
(NULL != p_session->dec_params.jpeg_cb)) {
p_session->job_status = JPEG_JOB_STATUS_ERROR;
CDBG("%s:%d] send jpeg error callback %d", __func__, __LINE__,
p_session->job_status);
p_session->dec_params.jpeg_cb(p_session->job_status,
p_session->client_hdl,
p_session->jobId,
NULL,
p_session->dec_params.userdata);
}
/*remove the job*/
mm_jpegdec_job_done(p_session);
CDBG("%s:%d] Error X ", __func__, __LINE__);
return rc;
}
/** mm_jpeg_start_decode_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_jpegdec_start_decode_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_decode_job_t *p_jobparams = &job->decode_job;
*job_id = 0;
/* check if valid session */
session_idx = GET_SESSION_IDX(p_jobparams->session_id);
client_idx = GET_CLIENT_IDX(p_jobparams->session_id);
CDBG("%s:%d] session_idx %d client idx %d", __func__, __LINE__,
session_idx, client_idx);
if ((session_idx >= MM_JPEG_MAX_SESSION) ||
(client_idx >= MAX_JPEG_CLIENT_NUM)) {
CDBG_ERROR("%s:%d] invalid session id %x", __func__, __LINE__,
job->decode_job.session_id);
return rc;
}
p_session = &my_obj->clnt_mgr[client_idx].session[session_idx];
if (OMX_FALSE == p_session->active) {
CDBG_ERROR("%s:%d] session not active %x", __func__, __LINE__,
job->decode_job.session_id);
return rc;
}
if ((p_jobparams->src_index >= (int32_t)p_session->dec_params.num_src_bufs) ||
(p_jobparams->dst_index >= (int32_t)p_session->dec_params.num_dst_bufs)) {
CDBG_ERROR("%s:%d] invalid buffer indices", __func__, __LINE__);
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) {
CDBG_ERROR("%s: No memory for mm_jpeg_job_q_node_t", __func__);
return -1;
}
*job_id = job->decode_job.session_id |
((p_session->job_hist++ % JOB_HIST_MAX) << 16);
memset(node, 0, sizeof(mm_jpeg_job_q_node_t));
node->dec_info.decode_job = job->decode_job;
node->dec_info.job_id = *job_id;
node->dec_info.client_handle = p_session->client_hdl;
node->type = MM_JPEG_CMD_TYPE_DECODE_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);
}
return rc;
}
/** mm_jpegdec_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_jpegdec_create_session(mm_jpeg_obj *my_obj,
uint32_t client_hdl,
mm_jpeg_decode_params_t *p_params,
uint32_t* p_session_id)
{
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;
*p_session_id = 0;
/* validate the parameters */
if ((p_params->num_src_bufs > MM_JPEG_MAX_BUF)
|| (p_params->num_dst_bufs > MM_JPEG_MAX_BUF)) {
CDBG_ERROR("%s:%d] invalid num buffers", __func__, __LINE__);
return rc;
}
/* check if valid client */
clnt_idx = mm_jpeg_util_get_index_by_handler(client_hdl);
if (clnt_idx >= MAX_JPEG_CLIENT_NUM) {
CDBG_ERROR("%s: invalid client with handler (%d)", __func__, client_hdl);
return rc;
}
session_idx = mm_jpeg_get_new_session_idx(my_obj, clnt_idx, &p_session);
if (session_idx < 0) {
CDBG_ERROR("%s:%d] invalid session id (%d)", __func__, __LINE__, session_idx);
return rc;
}
ret = mm_jpegdec_session_create(p_session);
if (OMX_ErrorNone != ret) {
p_session->active = OMX_FALSE;
CDBG_ERROR("%s:%d] jpeg session create failed", __func__, __LINE__);
return rc;
}
*p_session_id = (JOB_ID_MAGICVAL << 24) |
((unsigned)session_idx << 8) | clnt_idx;
/*copy the params*/
p_session->dec_params = *p_params;
p_session->client_hdl = client_hdl;
p_session->sessionId = *p_session_id;
p_session->jpeg_obj = (void*)my_obj; /* save a ptr to jpeg_obj */
CDBG("%s:%d] session id %x", __func__, __LINE__, *p_session_id);
return rc;
}
/** mm_jpegdec_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_jpegdec_destroy_session(mm_jpeg_obj *my_obj,
mm_jpeg_job_session_t *p_session)
{
int32_t rc = 0;
mm_jpeg_job_q_node_t *node = NULL;
if (NULL == p_session) {
CDBG_ERROR("%s:%d] invalid session", __func__, __LINE__);
return rc;
}
uint32_t session_id = p_session->sessionId;
pthread_mutex_lock(&my_obj->job_lock);
/* abort job if in todo queue */
CDBG("%s:%d] abort todo jobs", __func__, __LINE__);
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 */
CDBG("%s:%d] abort ongoing jobs", __func__, __LINE__);
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_jpegdec_session_destroy(p_session);
mm_jpeg_remove_session_idx(my_obj, session_id);
pthread_mutex_unlock(&my_obj->job_lock);
/* wake up jobMgr thread to work on new job if there is any */
cam_sem_post(&my_obj->job_mgr.job_sem);
CDBG("%s:%d] X", __func__, __LINE__);
return rc;
}
/** mm_jpegdec_destroy_session_by_id:
*
* Arguments:
* @my_obj: jpeg object
* @session_id: session index
*
* Return:
* 0 for success else failure
*
* Description:
* Destroy the encoding session
*
**/
int32_t mm_jpegdec_destroy_session_by_id(mm_jpeg_obj *my_obj, uint32_t session_id)
{
int32_t rc = 0;
mm_jpeg_job_session_t *p_session = mm_jpeg_get_session(my_obj, session_id);
if (NULL == p_session) {
CDBG_ERROR("%s:%d] session is not valid", __func__, __LINE__);
return rc;
}
return mm_jpegdec_destroy_session(my_obj, p_session);
}
OMX_ERRORTYPE mm_jpegdec_ebd(OMX_HANDLETYPE hComponent,
OMX_PTR pAppData,
OMX_BUFFERHEADERTYPE *pBuffer)
{
mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData;
CDBG("%s:%d] count %d ", __func__, __LINE__, 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_jpegdec_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;
CDBG("%s:%d] count %d ", __func__, __LINE__, p_session->fbd_count);
pthread_mutex_lock(&p_session->lock);
if (MM_JPEG_ABORT_NONE != p_session->abort_state) {
pthread_mutex_unlock(&p_session->lock);
return ret;
}
p_session->fbd_count++;
if (NULL != p_session->dec_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;
CDBG("%s:%d] send jpeg callback %d", __func__, __LINE__,
p_session->job_status);
p_session->dec_params.jpeg_cb(p_session->job_status,
p_session->client_hdl,
p_session->jobId,
&output_buf,
p_session->dec_params.userdata);
/* remove from ready queue */
mm_jpegdec_job_done(p_session);
}
pthread_mutex_unlock(&p_session->lock);
CDBG("%s:%d] ", __func__, __LINE__);
return ret;
}
OMX_ERRORTYPE mm_jpegdec_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;
CDBG("%s:%d] %d %d %d state %d", __func__, __LINE__, eEvent, (int)nData1,
(int)nData2, p_session->abort_state);
CDBG("%s:%d] AppData=%p ", __func__, __LINE__, pAppData);
pthread_mutex_lock(&p_session->lock);
p_session->omxEvent = eEvent;
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) {
if (p_session->encoding == OMX_TRUE) {
CDBG("%s:%d] Error during encoding", __func__, __LINE__);
/* send jpeg callback */
if (NULL != p_session->dec_params.jpeg_cb) {
p_session->job_status = JPEG_JOB_STATUS_ERROR;
CDBG("%s:%d] send jpeg error callback %d", __func__, __LINE__,
p_session->job_status);
p_session->dec_params.jpeg_cb(p_session->job_status,
p_session->client_hdl,
p_session->jobId,
NULL,
p_session->dec_params.userdata);
}
/* remove from ready queue */
mm_jpegdec_job_done(p_session);
}
pthread_cond_signal(&p_session->cond);
} else if (eEvent == OMX_EventCmdComplete) {
p_session->state_change_pending = OMX_FALSE;
p_session->event_pending = OMX_FALSE;
pthread_cond_signal(&p_session->cond);
} else if (eEvent == OMX_EventPortSettingsChanged) {
p_session->event_pending = OMX_FALSE;
pthread_cond_signal(&p_session->cond);
}
pthread_mutex_unlock(&p_session->lock);
CDBG("%s:%d]", __func__, __LINE__);
return OMX_ErrorNone;
}
/** mm_jpegdec_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_jpegdec_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;
CDBG("%s:%d] ", __func__, __LINE__);
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->dec_info.job_id);
if (p_session) {
mm_jpeg_session_abort(p_session);
} else {
CDBG_ERROR("%s:%d] Invalid job id 0x%x", __func__, __LINE__,
node->dec_info.job_id);
}
free(node);
goto abort_done;
}
abort_done:
pthread_mutex_unlock(&my_obj->job_lock);
return rc;
}
/** mm_jpegdec_init:
*
* Arguments:
* @my_obj: jpeg object
*
* Return:
* 0 for success else failure
*
* Description:
* Initializes the jpeg client
*
**/
int32_t mm_jpegdec_init(mm_jpeg_obj *my_obj)
{
int32_t rc = 0;
/* 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) {
CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
return -1;
}
/* init job semaphore and launch jobmgr thread */
CDBG("%s:%d] Launch jobmgr thread rc %d", __func__, __LINE__, rc);
rc = mm_jpeg_jobmgr_thread_launch(my_obj);
if (0 != rc) {
CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
return -1;
}
/* load OMX */
if (OMX_ErrorNone != OMX_Init()) {
/* roll back in error case */
CDBG_ERROR("%s:%d] OMX_Init failed (%d)", __func__, __LINE__, rc);
mm_jpeg_jobmgr_thread_release(my_obj);
mm_jpeg_queue_deinit(&my_obj->ongoing_job_q);
pthread_mutex_destroy(&my_obj->job_lock);
}
return rc;
}
/** mm_jpegdec_deinit:
*
* Arguments:
* @my_obj: jpeg object
*
* Return:
* 0 for success else failure
*
* Description:
* Deinits the jpeg client
*
**/
int32_t mm_jpegdec_deinit(mm_jpeg_obj *my_obj)
{
int32_t rc = 0;
/* release jobmgr thread */
rc = mm_jpeg_jobmgr_thread_release(my_obj);
if (0 != rc) {
CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
}
/* unload OMX engine */
OMX_Deinit();
/* deinit ongoing job and cb queue */
rc = mm_jpeg_queue_deinit(&my_obj->ongoing_job_q);
if (0 != rc) {
CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
}
/* destroy locks */
pthread_mutex_destroy(&my_obj->job_lock);
return rc;
}