text:
#include <pthread.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/prctl.h>
#include <fcntl.h>
#include <poll.h>
#include <math.h>

#include "mm_jpeg_dbg.h"
#include "mm_jpeg_interface.h"
#include "mm_jpeg.h"

/* define max num of supported concurrent jpeg jobs by OMX engine.
 * Current, only one per time */
#define NUM_MAX_JPEG_CNCURRENT_JOBS 1

#define JOB_ID_MAGICVAL 0x1
#define JOB_HIST_MAX 10000

/** DUMP_TO_FILE:
 *  @filename: file name
 *  @p_addr: address of the buffer
 *  @len: buffer length
 *
 *  dump the image to the file
 **/
#define DUMP_TO_FILE(filename, p_addr, len) ({ \
  int rc = 0; \
  FILE *fp = fopen(filename, "w+"); \
  if (fp) { \
    rc = fwrite(p_addr, 1, len, fp); \
    CDBG_HIGH("%s:%d] written size %d", __func__, __LINE__, len); \
    fclose(fp); \
  } else { \
    CDBG_ERROR("%s:%d] open %s failed", __func__, __LINE__, filename); \
  } \
})

/** DUMP_TO_FILE2:
 *  @filename: file name
 *  @p_addr: address of the buffer
 *  @len: buffer length
 *
 *  dump the image to the file if the memory is non-contiguous
 **/
#define DUMP_TO_FILE2(filename, p_addr1, len1, paddr2, len2) ({ \
  int rc = 0; \
  FILE *fp = fopen(filename, "w+"); \
  if (fp) { \
    rc = fwrite(p_addr1, 1, len1, fp); \
    rc = fwrite(p_addr2, 1, len2, fp); \
    CDBG_HIGH("%s:%d] written %d %d", __func__, __LINE__, len1, len2); \
    fclose(fp); \
  } else { \
    CDBG_ERROR("%s:%d] open %s failed", __func__, __LINE__, filename); \
  } \
})

/** MM_JPEG_CHK_ABORT:
 *  @p: client pointer
 *  @ret: return value
 *  @label: label to jump to
 *
 *  check the abort failure
 **/
#define MM_JPEG_CHK_ABORT(p, ret, label) ({ \
  if (OMX_TRUE == p->abort_flag) { \
    CDBG_ERROR("%s:%d] jpeg abort", __func__, __LINE__); \
    ret = OMX_ErrorNone; \
    goto label; \
  } \
})

#define GET_CLIENT_IDX(x) ((x) & 0xff)
#define GET_SESSION_IDX(x) (((x) >> 8) & 0xff)
#define GET_JOB_IDX(x) (((x) >> 16) & 0xff)

/** GCD:
 *  @x: input number
 *  @y: input number
 *  @gcd: gcd of x and y
 *
 *  Find the GCD of 2 numbers
 **/
#define GCD( x, y, gcd) ({ \
  int tmp; \
  while (*y != 0) { \
    tmp = *x % *y; \
    *x = *y; \
    *y = tmp; \
  } \
  *gcd = *x; \
})

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);

/** cirq_reset:
 *
 *  Arguments:
 *    @q: circular queue
 *
 *  Return:
 *       none
 *
 *  Description:
 *       Resets the circular queue
 *
 **/
static inline void cirq_reset(mm_jpeg_cirq_t *q)
{
  q->front = 0;
  q->rear = 0;
  q->count = 0;
  pthread_mutex_init(&q->lock, NULL);
}

/** cirq_empty:
 *
 *  Arguments:
 *    @q: circular queue
 *
 *  Return:
 *       none
 *
 *  Description:
 *       check if the curcular queue is empty
 *
 **/
#define cirq_empty(q) (q->count == 0)

/** cirq_full:
 *
 *  Arguments:
 *    @q: circular queue
 *
 *  Return:
 *       none
 *
 *  Description:
 *       check if the curcular queue is full
 *
 **/
#define cirq_full(q) (q->count == MM_JPEG_CIRQ_SIZE)

/** cirq_enqueue:
 *
 *  Arguments:
 *    @q: circular queue
 *    @data: data to be inserted
 *
 *  Return:
 *       true/false
 *
 *  Description:
 *       enqueue an element into circular queue
 *
 **/
#define cirq_enqueue(q, type, data) ({ \
  int rc = 0; \
  pthread_mutex_lock(&q->lock); \
  if (cirq_full(q)) { \
    rc = -1; \
  } else { \
    q->type[q->rear] = data; \
    q->rear = (q->rear + 1) % MM_JPEG_CIRQ_SIZE; \
    q->count++; \
  } \
  pthread_mutex_unlock(&q->lock); \
  rc; \
})

/** cirq_dequeue:
 *
 *  Arguments:
 *    @q: circular queue
 *    @data: data to be popped
 *
 *  Return:
 *       true/false
 *
 *  Description:
 *       dequeue an element from the circular queue
 *
 **/
#define cirq_dequeue(q, type, data) ({ \
  int rc = 0; \
  pthread_mutex_lock(&q->lock); \
  if (cirq_empty(q)) { \
    pthread_mutex_unlock(&q->lock); \
    rc = -1; \
  } else { \
    data = q->type[q->front]; \
    q->count--; \
  } \
  pthread_mutex_unlock(&q->lock); \
  rc; \
})

/**
 *
 * special queue functions for job queue
 **/
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_job_q_node_t* mm_jpeg_queue_remove_job_by_job_id(
  mm_jpeg_queue_t* queue, uint32_t job_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_job_q_node_t* mm_jpeg_queue_remove_job_unlk(
  mm_jpeg_queue_t* queue, uint32_t job_id);

/** mm_jpeg_pending_func_t:
 *
 * Intermediate function for transition change
 **/
typedef OMX_ERRORTYPE (*mm_jpeg_transition_func_t)(void *);

/** mm_jpeg_queue_func_t:
 *
 * Intermediate function for queue operation
 **/
typedef void (*mm_jpeg_queue_func_t)(void *);

/** 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;
  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;

  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 = 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;
    }
  }

  for (i = 0; i < p_params->num_tmb_bufs; i++) {
    CDBG("%s:%d] Source buffer %d", __func__, __LINE__, i);
    lbuffer_info.fd = 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) {
      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_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) {
      CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
      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_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;
  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;

  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_tmb_bufs; i++) {
    CDBG("%s:%d] Source buffer %d", __func__, __LINE__, i);
    ret = OMX_FreeBuffer(p_session->omx_handle, 2, p_session->p_in_omx_thumb_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_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;
  CDBG("%s:%d] new_state %d p_exec %p", __func__, __LINE__,
    new_state, p_exec);

  pthread_mutex_lock(&p_session->lock);

  ret = OMX_GetState(p_session->omx_handle, &current_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;
  ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandStateSet,
    new_state, NULL);
  if (ret) {
    CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
    pthread_mutex_unlock(&p_session->lock);
    return OMX_ErrorIncorrectStateTransition;
  }
  CDBG("%s:%d] ", __func__, __LINE__);
  if (OMX_ErrorNone != p_session->error_flag) {
    CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, 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) {
      CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
      pthread_mutex_unlock(&p_session->lock);
      return ret;
    }
  }
  CDBG("%s:%d] ", __func__, __LINE__);
  if (p_session->state_change_pending) {
    CDBG("%s:%d] before wait", __func__, __LINE__);
    pthread_cond_wait(&p_session->cond, &p_session->lock);
    CDBG("%s:%d] after wait", __func__, __LINE__);
  }
  pthread_mutex_unlock(&p_session->lock);
  CDBG("%s:%d] ", __func__, __LINE__);
  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_cirq_t *p_cirq = NULL;

  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_flag = OMX_FALSE;
  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->omx_callbacks.EmptyBufferDone = mm_jpeg_ebd;
  p_session->omx_callbacks.FillBufferDone = mm_jpeg_fbd;
  p_session->omx_callbacks.EventHandler = mm_jpeg_event_handler;
  rc = OMX_GetHandle(&p_session->omx_handle,
    "OMX.qcom.image.jpeg.encoder",
    (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_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;

  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_jpeg_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_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;
  int32_t i = 0;
  OMX_INDEXTYPE buffer_index;
  QOMX_YUV_FRAME_INFO frame_info;
  int32_t totalSize = 0;
  mm_jpeg_encode_params_t *p_params = &p_session->params;
  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;

  mm_jpeg_buf_t *p_src_buf =
    &p_params->src_main_buf[p_jobparams->src_index];

  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;
  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) {
    CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
    return rc;
  }

  CDBG_HIGH("%s:%d] yOffset = %d, cbcrOffset = (%d %d), totalSize = %d,"
    "cbcrStartOffset = (%d %d)", __func__, __LINE__,
    (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) {
    CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
    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;
  int32_t i = 0;
  OMX_INDEXTYPE indextype;
  QOMX_ENCODING_MODE encoding_mode;
  int32_t totalSize = 0;
  mm_jpeg_encode_params_t *p_params = &p_session->params;
  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;

  rc = OMX_GetExtensionIndex(p_session->omx_handle,
    QOMX_IMAGE_EXT_ENCODING_MODE_NAME, &indextype);
  if (rc != OMX_ErrorNone) {
    CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
    return rc;
  }

  CDBG_HIGH("%s:%d] OMX_Serial_Encoding = %d, OMX_Parallel_Encoding = %d ", __func__, __LINE__,
    (int)OMX_Serial_Encoding,
    (int)OMX_Parallel_Encoding);

  encoding_mode = OMX_Serial_Encoding;
  rc = OMX_SetParameter(p_session->omx_handle, indextype, &encoding_mode);
  if (rc != OMX_ErrorNone) {
    CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
    return rc;
  }
  return rc;
}

/** 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;
  default:
    CDBG_ERROR("%s:%d] invalid format %d", __func__, __LINE__, color_fmt);
    return (int)OMX_QCOM_IMG_COLOR_FormatYVU420SemiPlanar;
  }
}

/** 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;
  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_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;
  p_session->inputTmbPort.nPortIndex = 2;

  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->inputTmbPort);
  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 =
    p_jobparams->main_dim.src_dim.width;
  p_session->inputPort.format.image.nFrameHeight =
    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 =
    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 = 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;
  }

  if (p_session->params.encode_thumbnail) {
    mm_jpeg_buf_t *p_tmb_buf =
      &p_params->src_thumb_buf[p_jobparams->thumb_index];
    p_session->inputTmbPort.format.image.nFrameWidth =
      p_jobparams->thumb_dim.src_dim.width;
    p_session->inputTmbPort.format.image.nFrameHeight =
      p_jobparams->thumb_dim.src_dim.height;
    p_session->inputTmbPort.format.image.nStride =
      p_tmb_buf->offset.mp[0].stride;
    p_session->inputTmbPort.format.image.nSliceHeight =
      p_tmb_buf->offset.mp[0].scanline;
    p_session->inputTmbPort.format.image.eColorFormat =
      map_jpeg_format(p_params->color_format);
    p_session->inputTmbPort.nBufferSize =
      p_params->src_thumb_buf[p_jobparams->thumb_index].buf_size;
    p_session->inputTmbPort.nBufferCountActual = p_params->num_tmb_bufs;
    ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
      &p_session->inputTmbPort);

    if (ret) {
      CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
      return ret;
    }

    // Enable thumbnail port
    ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortEnable,
        p_session->inputTmbPort.nPortIndex, NULL);

    if (ret) {
      CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
      return ret;
    }
  } else {
    // Disable thumbnail port
    ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortDisable,
        p_session->inputTmbPort.nPortIndex, NULL);

    if (ret) {
      CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
      return ret;
    }
  }

  p_session->outputPort.nBufferSize =
    p_params->dest_buf[p_jobparams->dst_index].buf_size;
  p_session->outputPort.nBufferCountActual = p_params->num_dst_bufs;
  ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
    &p_session->outputPort);
  if (ret) {
    CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
    return ret;
  }

  return ret;
}

/** mm_jpeg_get_thumbnail_crop
 *
 *  Arguments:
 *    @p_thumb_dim: thumbnail dimension
 *    @p_main_dim: main image dimension
 *    @crop_width : flag indicating if width needs to be cropped
 *
 *  Return:
 *       OMX error values
 *
 *  Description:
 *    If the main image and thumbnail ascpect ratios are differnt,
 *    re-calculate the thumbnail crop info to prevent distortion
 *
 */
OMX_ERRORTYPE mm_jpeg_get_thumbnail_crop(mm_jpeg_dim_t *p_thumb_dim,
  mm_jpeg_dim_t *p_main_dim, uint8_t crop_width) {
  OMX_ERRORTYPE ret = OMX_ErrorNone;
  int divisor;
  int cropped_width = 0, cropped_height = 0;

  if(crop_width) {
   //Keep height constant
   cropped_height = p_thumb_dim->src_dim.height;
   cropped_width =  floor((cropped_height * p_thumb_dim->dst_dim.width) /
      p_thumb_dim->dst_dim.height);
  } else {
    //Keep width constant
    cropped_width =  p_thumb_dim->src_dim.width;
    cropped_height = floor((cropped_width * p_thumb_dim->dst_dim.height) /
      p_thumb_dim->dst_dim.width);
  }
  p_thumb_dim->crop.left = floor(p_thumb_dim->src_dim.width - cropped_width)/2;
  p_thumb_dim->crop.top = floor(p_thumb_dim->src_dim.height - cropped_height)/2;
  p_thumb_dim->crop.width = cropped_width;
  p_thumb_dim->crop.height = cropped_height;

  CDBG_HIGH("%s %d New thumbnail crop: left %d, top %d, crop width %d, crop height %d",
    __func__, __LINE__, 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;
  OMX_BOOL encode_thumbnail = OMX_FALSE;
  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];

  CDBG_HIGH("%s:%d] encode_thumbnail %d", __func__, __LINE__,
    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)) {
    CDBG_ERROR("%s:%d] Error invalid output dim for thumbnail",
      __func__, __LINE__);
    return OMX_ErrorBadParameter;
  }

  if ((p_thumb_dim->src_dim.width == 0) || (p_thumb_dim->src_dim.height == 0)) {
    CDBG_ERROR("%s:%d] Error invalid input dim for thumbnail",
      __func__, __LINE__);
    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)) {
    CDBG_ERROR("%s:%d] invalid crop boundary (%d, %d) offset (%d, %d) out of (%d, %d)",
      __func__, __LINE__,
      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) {
    CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
    return ret;
  }

  /* fill thumbnail info */
  thumbnail_info.scaling_enabled = 1;
  thumbnail_info.input_width = p_thumb_dim->src_dim.width;
  thumbnail_info.input_height = p_thumb_dim->src_dim.height;
  thumbnail_info.quality = p_params->thumb_quality;

  if ((p_main_dim->src_dim.width < p_thumb_dim->src_dim.width) ||
    (p_main_dim->src_dim.height < p_thumb_dim->src_dim.height)) {
    CDBG_ERROR("%s:%d] Improper thumbnail dim %dx%d resetting to %dx%d",
      __func__, __LINE__,
      p_thumb_dim->src_dim.width,
      p_thumb_dim->src_dim.height,
      p_main_dim->src_dim.width,
      p_main_dim->src_dim.height);
    thumbnail_info.input_width = p_main_dim->src_dim.width;
    thumbnail_info.input_height = p_main_dim->src_dim.height;
    if ((thumbnail_info.crop_info.nWidth > thumbnail_info.input_width)
      || (thumbnail_info.crop_info.nHeight > thumbnail_info.input_height)) {
      thumbnail_info.crop_info.nLeft = 0;
      thumbnail_info.crop_info.nTop = 0;
      thumbnail_info.crop_info.nWidth = thumbnail_info.input_width;
      thumbnail_info.crop_info.nHeight = thumbnail_info.input_height;
    }
  }

  //If the main image and thumbnail aspect ratio are different, reset the
  // thumbnail crop info to avoid distortion
  double main_aspect_ratio = (double)p_main_dim->dst_dim.width /
    (double)p_main_dim->dst_dim.height;
  double thumb_aspect_ratio = (double)p_thumb_dim->dst_dim.width /
    (double)p_thumb_dim->dst_dim.height;
  if ((thumb_aspect_ratio - main_aspect_ratio) > ASPECT_TOLERANCE) {
    mm_jpeg_get_thumbnail_crop(p_thumb_dim, p_main_dim, 0);
  } else if((main_aspect_ratio - thumb_aspect_ratio) > ASPECT_TOLERANCE){
    mm_jpeg_get_thumbnail_crop(p_thumb_dim, p_main_dim, 1);
  }

  //Fill thumbnail crop info
  thumbnail_info.crop_info.nWidth = p_thumb_dim->crop.width;
  thumbnail_info.crop_info.nHeight = 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;

  //If main image cropping/scaling is enabled, thumb FOV should be within
  //main image FOV
  if ((p_main_dim->crop.width != p_main_dim->src_dim.width) ||
    (p_main_dim->crop.height != p_main_dim->src_dim.height)) {
     if ((p_thumb_dim->crop.left < p_main_dim->crop.left) ||
       ((p_thumb_dim->crop.left + p_thumb_dim->crop.width) >
       (p_main_dim->crop.left + p_main_dim->crop.width)) ||
       (p_thumb_dim->crop.top < p_main_dim->crop.top) ||
       ((p_thumb_dim->crop.top + p_thumb_dim->crop.height) >
       (p_main_dim->crop.top + p_main_dim->crop.height))) {
       //Reset the FOV for the thumbnail
        CDBG_HIGH("%s:%d] Resetting the thumbnail FOV wrt main image",
          __func__, __LINE__);
       thumbnail_info.crop_info.nLeft = p_main_dim->crop.left;
       thumbnail_info.crop_info.nTop = p_main_dim->crop.height;
       if ((p_thumb_dim->crop.width > p_main_dim->crop.width) ||
         (p_thumb_dim->crop.height > p_main_dim->crop.height)) {
         thumbnail_info.crop_info.nWidth = p_main_dim->crop.width;
         thumbnail_info.crop_info.nHeight = p_main_dim->crop.height;
       }
    }
  }

  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)) {
    CDBG_ERROR("%s:%d] Incorrect thumbnail dim %dx%d resetting to %dx%d",
      __func__, __LINE__,
      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 = p_thumb_dim->src_dim.width;
    thumbnail_info.output_height = p_thumb_dim->src_dim.height;
  } else {
    thumbnail_info.output_width = p_thumb_dim->dst_dim.width;
    thumbnail_info.output_height = p_thumb_dim->dst_dim.height;
  }

  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;

  ret = OMX_SetConfig(p_session->omx_handle, thumb_indextype,
    &thumbnail_info);
  if (ret) {
    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
    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_params_t *p_params = &p_session->params;
  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)) {
    CDBG_ERROR("%s:%d] invalid crop boundary (%d, %d) out of (%d, %d)",
      __func__, __LINE__,
      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 = dim->dst_dim.width;
      rect_type_out.nHeight = dim->dst_dim.height;
    }
  }

  ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonInputCrop,
    &rect_type_in);
  if (OMX_ErrorNone != ret) {
    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
    return ret;
  }

  CDBG("%s:%d] OMX_IndexConfigCommonInputCrop w = %d, h = %d, l = %d, t = %d,"
    " port_idx = %d", __func__, __LINE__,
    (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) {
    CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
    return ret;
  }
  CDBG("%s:%d] OMX_IndexConfigCommonOutputCrop w = %d, h = %d,"
    " port_idx = %d", __func__, __LINE__,
    (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;
  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;

  /* config port */
  CDBG("%s:%d] config port", __func__, __LINE__);
  rc = mm_jpeg_session_config_ports(p_session);
  if (OMX_ErrorNone != rc) {
    CDBG_ERROR("%s: config port failed", __func__);
    return rc;
  }

  /* config buffer offset */
  CDBG("%s:%d] config main buf offset", __func__, __LINE__);
  rc = mm_jpeg_session_config_main_buffer_offset(p_session);
  if (OMX_ErrorNone != rc) {
    CDBG_ERROR("%s: config buffer offset failed", __func__);
    return rc;
  }

  /* set the encoding mode */
  mm_jpeg_encoding_mode(p_session);

  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;
  int i;
  OMX_INDEXTYPE exif_idx;
  OMX_CONFIG_ROTATIONTYPE rotate;
  mm_jpeg_encode_params_t *p_params = &p_session->params;
  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;
  rotate.nRotation = p_jobparams->rotation;
  rc = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonRotate,
    &rotate);
  if (OMX_ErrorNone != rc) {
      CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc);
      return rc;
  }
  CDBG("%s:%d] Set rotation to %d at port_idx = %d", __func__, __LINE__,
    (int)p_jobparams->rotation, (int)rotate.nPortIndex);

  /* Set Exif data*/
  memset(&p_session->exif_info_local[0], 0, sizeof(p_session->exif_info_local));

    /* set exif tags */
    rc = OMX_GetExtensionIndex(p_session->omx_handle, QOMX_IMAGE_EXT_EXIF_NAME,
      &exif_idx);
  if (OMX_ErrorNone != rc) {
    CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc);
    return rc;
  }
  CDBG_HIGH("%s:%d] Num of exif entries passed from HAL: %d", __func__, __LINE__,
      (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) {
      CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc);
      return rc;
    }
  }
  /*parse aditional exif data from the metadata if present*/
  if ((NULL != p_jobparams->p_metadata_v3) ||
    (NULL != p_jobparams->p_metadata_v1)) {
    exif_info.numOfEntries = 0;
    exif_info.exif_data = &p_session->exif_info_local[0];

    if (NULL != p_jobparams->p_metadata_v3) {
      process_meta_data_v3(p_jobparams->p_metadata_v3,
          &exif_info, &p_jobparams->cam_exif_params);
    } else {
      process_meta_data_v1(p_jobparams->p_metadata_v1,
        &exif_info, &p_jobparams->cam_exif_params);
    }
    /* After Parse metadata */
    p_session->exif_count_local = exif_info.numOfEntries;

    if (exif_info.numOfEntries > 0) {
      /* set exif tags */
      CDBG("%s:%d] exif tags from metadata count %d", __func__, __LINE__,
        (int)exif_info.numOfEntries);
      rc = OMX_SetConfig(p_session->omx_handle, exif_idx,
      &exif_info);
    if (OMX_ErrorNone != rc) {
      CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc);
      return rc;
      }
    }
  } else {
    CDBG_ERROR("%s:%d] Metadata is null", __func__, __LINE__, 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;

  CDBG("%s:%d] E", __func__, __LINE__);
  pthread_mutex_lock(&p_session->lock);
  if (OMX_TRUE == p_session->abort_flag) {
    pthread_mutex_unlock(&p_session->lock);
    CDBG("%s:%d] **** ALREADY ABORTED", __func__, __LINE__);
    return 0;
  }
  p_session->abort_flag = OMX_TRUE;
  if (OMX_TRUE == p_session->encoding) {
    p_session->state_change_pending = OMX_TRUE;

    CDBG("%s:%d] **** ABORTING", __func__, __LINE__);

    ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandStateSet,
    OMX_StateIdle, NULL);

    if (ret != OMX_ErrorNone) {
      CDBG("%s:%d] OMX_SendCommand returned error %d", __func__, __LINE__, ret);
      pthread_mutex_unlock(&p_session->lock);
      return 1;
    }
    ret = mm_jpeg_destroy_job(p_session);
    if (ret != 0) {
      CDBG("%s:%d] Destroy job returned error %d", __func__, __LINE__, rc);
    }

    CDBG("%s:%d] before wait", __func__, __LINE__);
    pthread_cond_wait(&p_session->cond, &p_session->lock);
    CDBG("%s:%d] after wait", __func__, __LINE__);
  }
  pthread_mutex_unlock(&p_session->lock);
  CDBG("%s:%d] X", __func__, __LINE__);
  return 0;
}

/** mm_jpeg_get_job_idx:
 *
 *  Arguments:
 *    @my_obj: jpeg object
 *    @client_idx: client index
 *
 *  Return:
 *       job index
 *
 *  Description:
 *       Get job index by client id
 *
 **/
static inline int mm_jpeg_get_new_session_idx(mm_jpeg_obj *my_obj, int client_idx,
  mm_jpeg_job_session_t **pp_session)
{
  int i = 0;
  int index = -1;
  for (i = 0; i < MM_JPEG_MAX_SESSION; i++) {
    pthread_mutex_lock(&my_obj->clnt_mgr[client_idx].lock);
    if (!my_obj->clnt_mgr[client_idx].session[i].active) {
      *pp_session = &my_obj->clnt_mgr[client_idx].session[i];
      my_obj->clnt_mgr[client_idx].session[i].active = OMX_TRUE;
      index = i;
      pthread_mutex_unlock(&my_obj->clnt_mgr[client_idx].lock);
      break;
    }
    pthread_mutex_unlock(&my_obj->clnt_mgr[client_idx].lock);
  }
  return index;
}

/** mm_jpeg_get_job_idx:
 *
 *  Arguments:
 *    @my_obj: jpeg object
 *    @client_idx: client index
 *
 *  Return:
 *       job index
 *
 *  Description:
 *       Get job index by client id
 *
 **/
static inline void mm_jpeg_remove_session_idx(mm_jpeg_obj *my_obj, uint32_t job_id)
{
  int client_idx =  GET_CLIENT_IDX(job_id);
  int session_idx= GET_SESSION_IDX(job_id);
  CDBG("%s:%d] client_idx %d session_idx %d", __func__, __LINE__,
    client_idx, session_idx);
  pthread_mutex_lock(&my_obj->clnt_mgr[client_idx].lock);
  my_obj->clnt_mgr[client_idx].session[session_idx].active = OMX_FALSE;
  pthread_mutex_unlock(&my_obj->clnt_mgr[client_idx].lock);
}

/** mm_jpeg_get_session_idx:
 *
 *  Arguments:
 *    @my_obj: jpeg object
 *    @client_idx: client index
 *
 *  Return:
 *       job index
 *
 *  Description:
 *       Get job index by client id
 *
 **/
static inline mm_jpeg_job_session_t *mm_jpeg_get_session(mm_jpeg_obj *my_obj, uint32_t job_id)
{
  mm_jpeg_job_session_t *p_session = NULL;
  int client_idx =  GET_CLIENT_IDX(job_id);
  int session_idx= GET_SESSION_IDX(job_id);

  CDBG("%s:%d] client_idx %d session_idx %d", __func__, __LINE__,
    client_idx, session_idx);
  if ((session_idx >= MM_JPEG_MAX_SESSION) ||
    (client_idx >= MAX_JPEG_CLIENT_NUM)) {
    CDBG_ERROR("%s:%d] invalid job id %x", __func__, __LINE__,
      job_id);
    return NULL;
  }
  pthread_mutex_lock(&my_obj->clnt_mgr[client_idx].lock);
  p_session = &my_obj->clnt_mgr[client_idx].session[session_idx];
  pthread_mutex_unlock(&my_obj->clnt_mgr[client_idx].lock);
  return p_session;
}

/** 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;
  mm_jpeg_encode_params_t *p_params = &p_session->params;
  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;

    /* common config */
  ret = mm_jpeg_session_config_common(p_session);
  if (OMX_ErrorNone != ret) {
    CDBG_ERROR("%s:%d] config common failed", __func__, __LINE__);

  }

  /* config Main Image crop */
  CDBG("%s:%d] config main crop", __func__, __LINE__);
  ret = mm_jpeg_session_config_main_crop(p_session);
  if (OMX_ErrorNone != ret) {
    CDBG_ERROR("%s: config crop failed", __func__);
    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);
  CDBG("%s:%d] config QFactor: %d", __func__, __LINE__, (int)q_factor.nQFactor);
  if (OMX_ErrorNone != ret) {
    CDBG_ERROR("%s:%d] Error setting Q factor %d", __func__, __LINE__, ret);
    return ret;
  }

  /* config thumbnail */
  ret = mm_jpeg_session_config_thumbnail(p_session);
  if (OMX_ErrorNone != ret) {
    CDBG_ERROR("%s:%d] config thumbnail img failed", __func__, __LINE__);
    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;
  mm_jpeg_encode_params_t *p_params = &p_session->params;
  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
  mm_jpeg_obj *my_obj = (mm_jpeg_obj *)p_session->jpeg_obj;

  CDBG("%s:%d] E ", __func__, __LINE__);

  MM_JPEG_CHK_ABORT(p_session, ret, error);

  /* config main img */
  ret = mm_jpeg_session_config_main(p_session);
  if (OMX_ErrorNone != ret) {
    CDBG_ERROR("%s:%d] config main img failed", __func__, __LINE__);
    goto error;
  }
  ret = mm_jpeg_session_change_state(p_session, OMX_StateIdle,
    mm_jpeg_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;
}

/** mm_jpeg_session_encode:
 *
 *  Arguments:
 *    @p_session: encode session
 *
 *  Return:
 *       OMX_ERRORTYPE
 *
 *  Description:
 *       Start the encoding
 *
 **/
static inline void mm_jpeg_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_jpeg_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_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_params_t *p_params = &p_session->params;
  mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
  int dest_idx = 0;
  mm_jpeg_obj *my_obj = (mm_jpeg_obj *)p_session->jpeg_obj;

  pthread_mutex_lock(&p_session->lock);
  p_session->abort_flag = OMX_FALSE;
  p_session->encoding = OMX_FALSE;
  pthread_mutex_unlock(&p_session->lock);

  if (OMX_FALSE == p_session->config) {
    ret = mm_jpeg_session_configure(p_session);
    if (ret) {
      CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
      goto error;
    }
    p_session->config = OMX_TRUE;
  }

  ret = mm_jpeg_configure_job_params(p_session);
  if (ret) {
      CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
      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);

#ifdef MM_JPEG_DUMP_INPUT
  DUMP_TO_FILE("/data/mm_jpeg_int.yuv",
    p_session->p_in_omx_buf[p_jobparams->src_index]->pBuffer,
    (int)p_session->p_in_omx_buf[p_jobparams->src_index]->nAllocLen);
#endif

  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;
  }

  if (p_session->params.encode_thumbnail) {
    ret = OMX_EmptyThisBuffer(p_session->omx_handle,
        p_session->p_in_omx_thumb_buf[p_jobparams->thumb_index]);
    if (ret) {
      CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
      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_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)
{
  int32_t rc = 0;
  OMX_ERRORTYPE ret = OMX_ErrorNone;
  mm_jpeg_job_session_t *p_session = NULL;
  mm_jpeg_job_q_node_t *node = NULL;

  /* check if valid session */
  p_session = mm_jpeg_get_session(my_obj, job_node->enc_info.job_id);
  if (NULL == p_session) {
    CDBG_ERROR("%s:%d] invalid job id %x", __func__, __LINE__,
      job_node->enc_info.job_id);
    return -1;
  }

  /* sent encode cmd to OMX, queue job into ongoing queue */
  rc = mm_jpeg_queue_enq(&my_obj->ongoing_job_q, job_node);
  if (rc) {
    CDBG_ERROR("%s:%d] jpeg enqueue failed %d",
      __func__, __LINE__, 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) {
    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->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->params.jpeg_cb(p_session->job_status,
      p_session->client_hdl,
      p_session->jobId,
      NULL,
      p_session->params.userdata);
  }

  /*remove the job*/
  mm_jpeg_job_done(p_session);
  CDBG("%s:%d] Error X ", __func__, __LINE__);

  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)
{
  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) {
        CDBG_ERROR("%s: cam_sem_wait error (%s)",
          __func__, strerror(errno));
        return NULL;
      }
    } while (rc != 0);

    /* check ongoing q size */
    num_ongoing_jobs = mm_jpeg_queue_get_size(&my_obj->ongoing_job_q);
    if (num_ongoing_jobs >= NUM_MAX_JPEG_CNCURRENT_JOBS) {
      CDBG("%s:%d] ongoing job already reach max %d", __func__,
        __LINE__, num_ongoing_jobs);
      continue;
    }

    pthread_mutex_lock(&my_obj->job_lock);
    /* can go ahead with new work */
    node = (mm_jpeg_job_q_node_t*)mm_jpeg_queue_deq(&cmd_thread->job_queue);
    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_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);
  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)
{
  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) {
    CDBG_ERROR("%s: No memory for mm_jpeg_job_q_node_t", __func__);
    return -1;
  }

  memset(node, 0, sizeof(mm_jpeg_job_q_node_t));
  node->type = MM_JPEG_CMD_TYPE_EXIT;

  mm_jpeg_queue_enq(&cmd_thread->job_queue, node);
  cam_sem_post(&cmd_thread->job_sem);

  /* wait until cmd thread exits */
  if (pthread_join(cmd_thread->pid, NULL) != 0) {
    CDBG("%s: pthread dead already", __func__);
  }
  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_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;

  /* 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_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;

  /* 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;
}

/** 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) {
    CDBG_ERROR("%s: num of clients reached limit", __func__);
    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;
}

/** 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)
{
  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  = &job->encode_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->encode_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->encode_job.session_id);
    return rc;
  }

  if ((p_jobparams->src_index >= p_session->params.num_src_bufs) ||
    (p_jobparams->dst_index >= p_session->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->encode_job.session_id |
    ((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;
  node->enc_info.job_id = *job_id;
  node->enc_info.client_handle = p_session->client_hdl;
  node->type = MM_JPEG_CMD_TYPE_JOB;

  rc = mm_jpeg_queue_enq(&my_obj->job_mgr.job_queue, node);
  if (0 == rc) {
    cam_sem_post(&my_obj->job_mgr.job_sem);
  }

  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;
  uint8_t clnt_idx = 0;
  mm_jpeg_job_q_node_t *node = NULL;
  OMX_BOOL ret = OMX_FALSE;
  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->enc_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->enc_info.job_id);
    }
    free(node);
    goto abort_done;
  }

abort_done:
  pthread_mutex_unlock(&my_obj->job_lock);

  return rc;
}

/** 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)
{
  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 -1;
  }

  /* 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 -1;
  }

  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 -1;
  }

  ret = mm_jpeg_session_create(p_session);
  if (OMX_ErrorNone != ret) {
    p_session->active = OMX_FALSE;
    CDBG_ERROR("%s:%d] jpeg session create failed", __func__, __LINE__);
    return ret;
  }

  *p_session_id = (JOB_ID_MAGICVAL << 24) | (session_idx << 8) | clnt_idx;

  /*copy the params*/
  p_session->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 ret;
}
/** mm_jpeg_destroy_job
 *
 *  Arguments:
 *    @p_session: Session obj
 *
 *  Return:
 *       0 for success else failure
 *
 *  Description:
 *       Destroy the job based paramenters
 *
 **/
int32_t mm_jpeg_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;

  CDBG_HIGH("%s:%d] Exif entry count %d %d", __func__, __LINE__,
    (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) {
      CDBG_ERROR("%s:%d] Exif release failed (%d)", __func__, __LINE__, rc);
    }
  }
  p_session->exif_count_local = 0;

  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(mm_jpeg_obj *my_obj,
  mm_jpeg_job_session_t *p_session)
{
  int32_t rc = 0;
  uint8_t clnt_idx = 0;
  mm_jpeg_job_q_node_t *node = NULL;
  OMX_BOOL ret = OMX_FALSE;
  uint32_t session_id = p_session->sessionId;

  if (NULL == p_session) {
    CDBG_ERROR("%s:%d] invalid session", __func__, __LINE__);
    return rc;
  }

  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_jpeg_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_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;
  uint8_t clnt_idx = 0;
  mm_jpeg_job_q_node_t *node = NULL;
  OMX_BOOL ret = OMX_FALSE;
  uint32_t session_id = p_session->sessionId;

  if (NULL == p_session) {
    CDBG_ERROR("%s:%d] invalid session", __func__, __LINE__);
    return rc;
  }

  /* 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_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;
  mm_jpeg_job_q_node_t *node = NULL;
  OMX_BOOL ret = OMX_FALSE;
  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) {
    CDBG_ERROR("%s: invalid client with handler (%d)", __func__, client_hdl);
    return rc;
  }

  CDBG("%s:%d] E", __func__, __LINE__);

  /* abort all jobs from the client */
  pthread_mutex_lock(&my_obj->job_lock);

  CDBG("%s:%d] ", __func__, __LINE__);

  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]);
  }

  CDBG("%s:%d] ", __func__, __LINE__);

  pthread_mutex_unlock(&my_obj->job_lock);
  CDBG("%s:%d] ", __func__, __LINE__);

  /* 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;
  CDBG("%s:%d] X", __func__, __LINE__);
  return rc;
}

OMX_ERRORTYPE mm_jpeg_ebd(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;

  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_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;
  uint32_t i = 0;
  int rc = 0;
  mm_jpeg_output_t output_buf;

  CDBG("%s:%d] count %d ", __func__, __LINE__, p_session->fbd_count);

  if (OMX_TRUE == p_session->abort_flag) {
    pthread_cond_signal(&p_session->cond);
    return ret;
  }

  pthread_mutex_lock(&p_session->lock);
  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 = 0;
    CDBG("%s:%d] send jpeg callback %d", __func__, __LINE__,
      p_session->job_status);
    p_session->params.jpeg_cb(p_session->job_status,
      p_session->client_hdl,
      p_session->jobId,
      &output_buf,
      p_session->params.userdata);

    /* remove from ready queue */
    mm_jpeg_job_done(p_session);
  }
  pthread_mutex_unlock(&p_session->lock);
  CDBG("%s:%d] ", __func__, __LINE__);

  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;

  CDBG("%s:%d] %d %d %d", __func__, __LINE__, eEvent, (int)nData1,
    (int)nData2);

  pthread_mutex_lock(&p_session->lock);

  if (OMX_TRUE == p_session->abort_flag) {
    pthread_cond_signal(&p_session->cond);
    pthread_mutex_unlock(&p_session->lock);
    return OMX_ErrorNone;
  }

  if (eEvent == OMX_EventError) {
    p_session->error_flag = OMX_ErrorHardware;
    if (p_session->encoding == OMX_TRUE) {
      CDBG("%s:%d] Error during encoding", __func__, __LINE__);

      /* send jpeg callback */
      if (NULL != p_session->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->params.jpeg_cb(p_session->job_status,
          p_session->client_hdl,
          p_session->jobId,
          NULL,
          p_session->params.userdata);
      }

      /* remove from ready queue */
      mm_jpeg_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);
  CDBG("%s:%d]", __func__, __LINE__);
  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;

    if (data && (data->enc_info.client_handle == client_hdl)) {
      CDBG_HIGH("%s:%d] found matching client handle", __func__, __LINE__);
      job_node = data;
      cam_list_del_node(&node->list);
      queue->size--;
      free(node);
      CDBG_HIGH("%s: queue size = %d", __func__, 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;

    if (data && (data->enc_info.encode_job.session_id == session_id)) {
      CDBG_HIGH("%s:%d] found matching session id", __func__, __LINE__);
      job_node = data;
      cam_list_del_node(&node->list);
      queue->size--;
      free(node);
      CDBG_HIGH("%s: queue size = %d", __func__, 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;

  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;

    if (data && (data->enc_info.job_id == job_id)) {
      CDBG_HIGH("%s:%d] found matching job id", __func__, __LINE__);
      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;

    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;
}


Kevin received his BFA in Graphic Design from the College for Creative Studies in Detroit, Michigan, and after working as an Art Director in New York and Philadelphia, started his own design & Illustration business before receiving his MFA in Sculpture from Southern Illinois University in Carbondale, Illinois in 2008.
Moving to Colorado in late 2009, Kevin has served as Adjunct Faculty at DU since 2010 and Regis University since early 2012. In that time, has been awarded public art commissions by the City of Denver (to be located on Tennyson and 41st) and RTD for Denver's new transportation hub based at the Historic Union Station as well as solo exhibitions at Colorado State University and Rule Gallery in Denver.
Over the past four years, Kevin has been an Artist-in-Residence at Lawndale Art Center in Houston, TX, Art342 in Fort Collins, Colorado, Platteforum in Denver, Colorado and is currently a resident artist at RedLine in Denver, Colorado. 2013 will see Kevin at residencies at Kimmel-Harding in Nebraska and on the south rim of the Grand Canyon as part of the National Parks Artist-in-Residence program.


, we selects the best choices with ideal resolution exclusively for you all, and now this pictures is one of photos collections within our best graphics gallery about Elegant University Of Chicago Emergency Room. I hope you may enjoy it.
published simply by Zeeb from 2017-01-13 05:16:53. To view all images with Elegant University Of Chicago Emergency Room images gallery remember to adhere to this website link.


From brushed flats, polished slides, to Cerakote camouflage – we can handle it all. We do Cerakote right, as always, paying attention to the small details that make the whole. Single colors to multi-color themes and patters, we can handle the job for you. As part of a full build, or on it's own, talk to us about your next firearm refinishing project.


text:
CAB: UN chief wants laws to be non-discriminatory
Diplomacy, International, Politics, Rights December 11, 2019, 9:59 am Daily World
By Arul Louis
United Nations, Dec 11 : Secretary-General Antonio Guterres wants laws to be non-discriminatory, but will not comment on India's Citizenship (Amendment) Bill (CAB) while the legislative process is still underway, according to his spokesperson.
Asked at the daily briefing on Tuesday by a reporter about the bill that was passed on Monday midnight by the Lok Sabha, Deputy Spokesperson Farhan Haq said: "As far as I'm aware, this is legislation that is continuing to go through the legislative process. So, we wouldn't have any comment while the domestic legislative process is being carried out."
But he added, "At the same time, you're aware of what our concerns are about making sure that all governments pursue non-discriminatory laws."
In phrasing his question the reporter said the bill, which has yet to be passed by the Rajya Sabha, discriminated against Muslims.
The intent of the bill, though, is to help victims of religious persecution.
It seeks to provide refuge to Hindus, Christians, Sikhs, Buddhists, Parsis and Jains fleeing religious persecution from the officially Islamic Pakistan and Afghanistan and Muslim-majority Bangladesh.
(Arul Louis can be contacted at arul.l@ians.in and followed on Twitter @arulouis)
Diplomacy, International, politics, Rights
Special train service planned for U2 India gig
Five dead in hotel attack in Somali capital: police.

redpajama_set_name: RedPajamaCommonCrawl


text:
Monday, November 6th, 2017
with Palm, Lala Lala
Admission: $15 | All Ages
Life has been a whirl for Girlpool since the release of their acclaimed 2015 debut Before the World Was Big. Shortly before the record came out, Harmony Tividad (she/her) and Cleo Tucker (they/them) relocated from their hometown of Los Angeles all the way across the country to Philadelphia, where they quickly became embedded in the local D.I.Y. scene. "Before BTWWB, I was just out of high school, living in my old neighborhood," recalls Cleo Tucker. "Then we started touring in a way we'd never done before. I really started to experience the duality that was beginning to exist in my life: tour/not on tour." After a chaotic and informative year spent floating around the East Coast, both bandmates moved home to California at the start of 2017. Girlpool have been seemingly everywhere at once, exploring all the world's offerings with open minds and notebooks. All the lessons they learned, about the earth and about themselves, are gathered together in their sophomore record and ANTI- debut, Powerplant.
Over 10 days in August 2016, Girlpool holed up at Los Angeles' Comp-ny studios to record and mix Powerplant with Drew Fischer. For the first time, Harmony and Cleo were joined by a third performer, drummer Miles Wintner, a friend who easily meshed with the tightknit duo. The decision to add percussion came as a natural decision for Harmony and Cleo; "Cleo and I just were driving down the New Jersey turnpike when she mentioned that it might be exciting to expand our sound for the new songs," says Harmony. "The songs we were writing had the potential of getting really climactic," adds Cleo. "I think percussion adds a new part of the musical dynamic that we want to explore."Girlpool's eagerness to evolve should come as no surprise; in the same way that there were little traces of their self-titled EP on BTWWB, on Powerplant, the pair shed their old skins with more eagerness than before. "In some ways I feel more courageous and mature and in other ways I feel smaller and softer, sometimes even more fragile than ever," says Harmony, adding that while the inner self is always changing, ultimately the end is a closer self-truth.
The 12 tracks that compose Powerplant grow and burn with greater fire than the duo have possessed heretofore. Both bandmates were heavily inspired by Elliott Smith, the Cranberries, the Cocteau Twins, Brian Eno, Arthur Russell, and Graham Nash; the influence of each appear in the record's deliberate and intricate guitar work ("Fast Dust," "She Goes By") as well as its embrace of dissonant noise ("Corner Store," "Soup"). Though they were living apart for most of the writing process, the pair still managed to write all but four songs together, another testament to their dedication to Girlpool and each other. Now 21 and 20, Harmony and Cleo confront projections, despondency, apathy, romanticization, love, and heartbreak with a more devastating emotional pragmatism than before. "Looking pretty at the wall is my mistake in love installed/While the moth doesn't talk but in the dress the holes you saw," they sing on opener "123," perfectly refracting the truth. More humorous (but still heavily symbolic) lines are delivered with equal poignancy, like Harmony's disclaimer on "It Gets More Blue," "The nihilist tells you that nothing is true/I said I faked global warming just to get close to you."
Both bandmates believe that radical vulnerability and honesty are essential to discovering oneself. "I see vulnerable softness as a place where the honest self can come forward," Cleo explains, saying that on Powerplant, Girlpool aimed for sincere expression. "As a society I feel that we perceive softness and vulnerability as traits that are 'weak,' and people emotionally disconnect themselves in order to avoid going through everything they feel," Harmony adds. "I think what is most important right now is empathy, and in order to have empathy we must first feel what we, ourselves, feel." Perhaps what really makes Powerplant a home run is that Girlpool understand exactly how to use their incisive lyrics, soft textures, hushed harmonies, and soaring hooks for maximum emotional impact. In these moments, when Harmony and Cleo's voices join together to deliver transcendent transmissions straight from their hearts, Girlpool become a league of their own.
Palm plays rock music backwards. Their songs bear a certain methodology, though there is a tendency towards impulse which seems almost violently opposed to it. The band deals willfully in contradictions like this. The elements of any given song fit together like slightly melted puzzle pieces, serving up rigidity and looseness in equal measure. Palm songs imply architecture, but their compositional structures are somehow bound by different rules of physics than the ones we know. Lattices of guitar language (provided by Eve Alpert and Kasra Kurt) intersect the rhythmic organism characterized by the twitchy throb of Gerasimos Livitsanos' bass and the careless tumble of Hugo Stanley's drums, with a layer of disembodied vocals draped atop the whole thing. Emotional yet clinical, wild yet contained, the sounds they offer are equally bizarre as they are pleasantly pretty.
Palm formed around 2011, shortly after its members met in college in Upstate New York. The years they spent writing and playing when not in school culminated into the release of Trading Basics in 2015, around which time they relocated to Philadelphia. Since then they've been playing shows throughout the country while they continue to hammer out their sound to be as refined as it is outlandish. More to come.
https://palmnewyork.bandcamp.com/


text:
class AnnotationsController < ApplicationController
  include DC::Access

  layout false

  before_action :login_required, :except => [:index, :show, :print,:cors_options]
  skip_before_action :verify_authenticity_token

  # In the workspace, request a listing of annotations.
  def index
    annotations = current_document.annotations_with_authors(current_account)
    json annotations
  end

  def show
    return not_found unless current_annotation
    respond_to do |format|
      format.json do
        @response = current_annotation.canonical(:include_image_url => true, :include_document_url => true)
        # TODO: https://github.com/documentcloud/documentcloud/issues/291
        # cache_page @response.to_json if current_annotation.cacheable?
        json_response
      end
      format.js do
        json = current_annotation.canonical(:include_image_url => true, :include_document_url => true).to_json
        js = "dc.embed.noteCallback(#{json})"
        cache_page js if current_annotation.cacheable?
        render :js => js
      end
      format.html do
        render
      end
    end
  end

  # Print out all the annotations for a document (or documents.)
  def print
    docs = Document.accessible(current_account, current_organization).where( :id => params[:docs] )
    Document.populate_annotation_counts(current_account, docs)
    @documents_json = docs.map {|doc| doc.to_json(:annotations => true, :account => current_account) }
    render :layout => false
  end

  # Any account can create a private note on any document.
  # Only the owner of the document is allowed to create a public annotation.
  def create
    maybe_set_cors_headers
    note_attrs = pick(params, :page_number, :title, :content, :location, :access)
    note_attrs[:access] = ACCESS_MAP[note_attrs[:access].to_sym]
    doc = current_document
    return forbidden unless note_attrs[:access] == PRIVATE || current_account.allowed_to_comment?(doc)
    expire_pages doc.cache_paths if doc.cacheable?
    note_attrs[:organization_id] = current_account.organization_id
    anno = doc.annotations.create(note_attrs.merge(
      :account_id      => current_account.id
    ))
    json current_document.annotations_with_authors(current_account, [anno]).first
  end

  # You can only alter annotations that you've made yourself.
  def update
    maybe_set_cors_headers
    return not_found unless anno = current_annotation
    if !current_account.allowed_to_edit?(anno)
      anno.errors.add(:base, "You don't have permission to update the note.")
      return json(anno, 403)
    end
    attrs = pick(params, :title, :content, :access)
    attrs[:access] = DC::Access::ACCESS_MAP[attrs[:access].to_sym]
    anno.update_attributes(attrs)
    expire_pages current_document.cache_paths if current_document.cacheable?
    expire_pages current_annotation.cache_paths if current_annotation.cacheable?
    anno.reset_public_note_count
    json anno
  end

  def destroy
    maybe_set_cors_headers
    return not_found unless anno = current_annotation
    if ! current_account.allowed_to_edit?(anno)
      anno.errors.add(:base, "You don't have permission to delete the note.")
      return json(anno, 403)
    end
    anno.destroy
    expire_pages current_document.cache_paths if current_document.cacheable?
    json nil
  end

  def cors_options
    return bad_request unless params[:allowed_methods]
    maybe_set_cors_headers
    render :nothing => true
  end

  private

  def current_annotation
    @current_annotation ||= current_document.annotations.find_by_id(params[:id])
  end

  def current_document
    @current_document ||= Document.accessible(current_account, current_organization).find(params[:document_id])
  end

end

redpajama_set_name: RedPajamaGithub


A new feature in the iPhone operating system shows how much time you spend on your phone.
You'll be able to download it this fall.
People are going to be shocked about the number of hours per day they spend on their phone.
I've never had a software update cause me to rethink my lifestyle, but the latest version of the iPhone operating system forced me to take a hard look at myself – and my relationship with my iPhone.
And when everyone gets access to iOS 12 this fall, it's going to surprise millions of people.
Tucked into the updated iPhone settings menu is a new collection of features called Screen Time. It collects data on how many times you use your phone and how many times you pick it up. It also includes statistics on which apps you use most, and how many notifications you receive.
An example Screen Time screenshot. Not my stats.
Reader, I was shocked. This week, I picked up my phone about 248 times per day on average. I use my phone for so many hours on a daily basis I'm embarrassed to share the exact number, but it's upwards of 5 hours.
Before I looked at these stats, I didn't think I had a phone problem. I've actively tried to limit notifications, and I try really hard not to check my phone during meetings or conversations, so I'm not being rude to people around me.
I'm still not sure if I have a phone problem, but I may simply be in denial. The fact is that I'm using my phone for a huge number of my waking hours – a way higher percentage than I would have guessed without these stats.
I'm not alone in being surprised at the statistics in Apple's Screen Time feature. At Apple's annual developer conference, which took place in San Jose, California earlier this month, hundreds of software engineers downloaded and installed the beta version of iOS with Screen Time, and many of them were surprised too.
The Screen Time feature was a common topic of conversation among the people who had travelled to California to learn how to best make software for Apple computers. But like myself, many attendees who would discuss phone overuse in general were also hesitant to share their official stats, as if they were an embarrassing secret.
Even Apple's CEO, Tim Cook, said that the numbers surprised him.
Which apps was he using the most?
According to Cook, though, Apple isn't worried that giving this information to users could impact Apple's business.
There is some hope that Apple's new features – as well as similar updates from Google – may start changing the focus around digital health and and shifting cultural assumptions and conventions.
"This will set a new direction and new race to the top for who cares more about protecting human values," Tristan Harris, a former Google designer who has become a digital health activist, tweeted after Apple announced Screen Time.
But now, the features seem to be advisory. They're tools to assess your phone usage, not to fix it. They're not going to change people's habits by themselves.
I turned on a Screen Time feature called Downtime. By default, after 10 p.m. it locked me out of every app that wasn't a core feature like calls and texts, including all games and all social networks. I couldn't check Twitter or use Safari until the morning. In practice, it's a lot like a stripped-down "essential mode" suggested by several groups, including Stanford Students Against Addictive Devices.
For me, it worked – for the most part I didn't use my phone after 10. But I ended up checking Twitter or playing games on my laptop or iPad instead. There was also an option to ignore the time limit and use a blocked app anyway, although I never did.
In my weeklong experience with Screen Time, I realized that the features by themselves aren't going to reduce a heavy user's daily time, although Apple's Screen Time does let you set time limits (that the user can override.) But just knowing the scope of the problem is the first step.
"Empowering people with the facts, will allow them to decide themselves how they want to cut back, or if they want to cut back," Cook said in the CNN interview.
For me, the facts have told me that I need to cut back. We'll see if iOS 12 this fall prompts millions of others to do the same.


text:
NOV 16 - 18 | 2021
Koelnmesse | Germany
About EUROPEAN ROTORS
Application & Services
Drone Pavilion
Application universities
COVID-19 Guidelines Exhibitors
Exhibitor Service
Exhibiting Guidelines
Construction & Dismantling time
EUROPEAN ROTORS Business Report
A well-known personality visit
About our Programme
EUROPEAN ROTORS DIGITAL SERIES
EASA Rotorcraft Symposium
Tickets & Visiting
COVID-19 Guidelines Visitors
Press appointments
New helicopter
show in Cologne
#europeanrotors
The new & unique helicopter show
EUROPEAN ROTORS
New show format for Europe's rotorcraft industry including an international range of exhibitors and a safety conference – Cooperation between European Helicopter Association (EHA) and European Union Aviation Safety Agency (EASA)
For the first time, the European Helicopter Association (EHA) and the European Union Aviation Safety Agency (EASA) are joining forces to offer the international rotorcraft community a unique event format. In keeping with the claim "If you are rotors – we got it!", the new show will be creating a global network platform for the helicopter industry from November 10th - 12th 2020 at Koelnmesse, Germany. It will also integrate the renowned EASA Rotorcraft and VTOL Symposium. VTOL stands for vertical take-off and landing, and mainly refers to the new development of electrical or hybrid innovative vehicles with advance level of autonomy, which play an important role in the development of the entire sector – either complementing helicopter missions or as a new form of airborne mobility.
The market leaders Airbus, Bell, Leonardo and Safran are supporting the new format both through their presence as exhibitors and with an advisory function. "I am proud to announce the launch of EUROPEAN ROTORS in cooperation with EASA and with the great support of all our members", declared Peter Möller, Chairman of the organisers, European Helicopter Association, at the opening press conference on 21 January in Cologne, Germany. "The new gathering for the industry marks an important milestone in our endeavours to promote the social and economic value of rotorcraft operations for European society. We will offer operators, manufacturers, aviation authorities, the supporting industry, mechanics, pilots, customers and suppliers the opportunity to network and also to be informed on state-of-the-art equipment and services. Visitors will additionally have the chance to discuss present and future regulations as well as to participate in dedicated training."
Another fundamental component of the three-day event will be the integration of the renowned EASA Rotorcraft and VTOL Symposium. David Solar, Head of VTOL Department at EASA explained: "Through our participation in EUROPEAN ROTORS, in collaboration with EHA, we are integrating our very successful and established Rotorcraft and VTOL Symposium to reach out to the broader industry, enabling better collaboration and mutual understanding to enhance global aviation safety. Direct exchange with manufacturers, operators, Approved Training Organisations (ATOs) and maintenance organisations will provide us with valuable 360° feedback for our work."
The venue for EUROPEAN ROTORS will be Hall 8 and the Congress Centre North of Koelnmesse, Germany. Beside the organisers, the service partner is Messe Friedrichshafen, an experienced exhibition and fairs company, which also stages the established aviation show AERO Friedrichshafen. Alongside the exhibition section, an additional focus of EUROPEAN ROTORS will be on the varied conference components with a large number of seminars and individual training sessions that visitors can book.
In keeping with the motto of EUROPEAN ROTORS "It's for everyone", the show also aims to present topics for the general public and political leaders on a separate stage inside the exhibition hall, thus increasing interest in helicopters. Recruitment also plays a prominent role for the industry, which is why there are favourable conditions for students and free admission for everyone as from the afternoon of the third day.
The major involvement of the leading Original Equipment Manufacturers (OEMs) is an additional added value for the three-day industry gathering, and Luc Bentolila, Airbus VP Marketing & Sales Development is already firmly convinced of this: "50 years ago, Europe was giving birth to Airbus so we are thrilled to be supporting the EHA and EASA VTOL show and safety conference. We expect high quality discussions and exchanges within the industry, especially at a time of transition to new technologies and environmental challenges. Understanding and anticipating the needs of our customers to increase the performance and safety of their operations will be essential in order to continue leading the market by delivering state-of the-art solutions."
Roberto Garavaglia, Leonardo Helicopters SVP strategy and innovation, has similarly high expectations: "Europe is the world's largest helicopter market, a benchmark for other emerging economies enhancing their helicopter services or even introducing all new ones. The continent stays at the forefront of technological and regulatory innovation and OEMs are, by definition, a crucial element of such competitiveness. That is why Leonardo believes a new, strong dedicated exhibition is needed, allowing all the relevant players to meet, assess the state of the industry and define the next steps."
Patrick Moulay, Bell Senior Vice President, Commercial Business - International continues: "Bell is proud to support the new EUROPEAN ROTORS event. We thank the European Helicopter Association for bringing together the vertical lift industry and the aviation authorities to focus on the benefits and positive impact of helicopters on society, today and in the future. This event will be a driving force for the advancement of VTOL throughout Europe."
"Safran wants the new EUROPEAN ROTORS show to be a powerful event for the European helicopter community and the general public", says Franck Saudo, CEO Safran Helicopter Engines. It is a unique opportunity to bring together actors within the helicopter and VTOL industries in the same location, centrally in Europe. Exhibitions, conferences, best-practice seminars and networking will make it an indispensable event; one in which Safran intends to have a growing stake."
EUROPEAN ROTORS is the VTOL Show and Safety Conference. It will be taking place from Tuesday 10 November to Thursday 12 November 2020. The venue will be Hall 8 and the Congress Centre North of Koelnmesse, Germany, with access via Entrance North. Further information, including opening times and prices, is available at www.europeanrotors.eu. Social media channels: www.twitter.com/europeanrotors, https://www.linkedin.com/showcase/european-rotors and www.instagram.com/europeanrotors, #europeanrotors
Initial press conference
International Press Conference on Tuesday, January 21, 2020 hosted by EHA & EASA about a new show taking place in Cologne
Download Exhibitor Brochure
Stay open for new possibilities
We offer exclusive content for subscribers
Neue Messe 1
Messe Friedrichshafen