C++程序  |  582行  |  16.79 KB

/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 *       copyright notice, this list of conditions and the following
 *       disclaimer in the documentation and/or other materials provided
 *       with the distribution.
 *     * Neither the name of The Linux Foundation nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

// To remove
#include <utils/Log.h>

// System dependencies
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/types.h>

// Camera dependencies
#include "img_common.h"
#include "img_comp.h"
#include "img_comp_factory.h"
#include "img_buffer.h"
#include "lib2d.h"
#include "mm_lib2d.h"

/** lib2d_job_private_info
 * @jobid: Job id of this process request
 * @userdata: Client userdata that will be passed on callback
 * @lib2d_client_cb: Application's callback function pointer
 *     which will be called upon completion of current job.
**/
typedef struct lib2d_job_private_info_t {
  int   jobid;
  void *userdata;
  lib2d_error (*lib2d_client_cb) (void *userdata, int jobid);
} lib2d_job_private_info;

/** img_lib_t
 * @ptr: handle to imglib library
 * @img_core_get_comp: function pointer for img_core_get_comp
 * @img_wait_for_completion: function pointer for img_wait_for_completion
**/
typedef struct {
  void *ptr;
  int (*img_core_get_comp) (img_comp_role_t role, char *name,
    img_core_ops_t *p_ops);
  int (*img_wait_for_completion) (pthread_cond_t *p_cond,
    pthread_mutex_t *p_mutex, int32_t ms);
} img_lib_t;

/** mm_lib2d_obj
 * @core_ops: image core ops structure handle
 * @comp: component structure handle
 * @comp_mode: underlying component mode
 * @lib2d_mode: lib2d mode requested by client
 * @img_lib: imglib library, function ptrs handle
 * @mutex: lib2d mutex used for synchronization
 * @cond: librd cond used for synchronization
**/
typedef struct mm_lib2d_obj_t {
  img_core_ops_t      core_ops;
  img_component_ops_t comp;
  img_comp_mode_t     comp_mode;
  lib2d_mode          lib2d_mode;
  img_lib_t           img_lib;
  pthread_mutex_t     mutex;
  pthread_cond_t      cond;
} mm_lib2d_obj;


/**
 * Function: lib2d_event_handler
 *
 * Description: Event handler. All the component events
 *     are received here.
 *
 * Input parameters:
 *   p_appdata - lib2d test object
 *   p_event - pointer to the event
 *
 * Return values:
 *   IMG_SUCCESS
 *   IMG_ERR_INVALID_INPUT
 *
 * Notes: none
 **/
int lib2d_event_handler(void* p_appdata, img_event_t *p_event)
{
  mm_lib2d_obj *lib2d_obj = (mm_lib2d_obj *)p_appdata;

  if ((NULL == p_event) || (NULL == p_appdata)) {
    LOGE("invalid event");
    return IMG_ERR_INVALID_INPUT;
  }

  LOGD("type %d", p_event->type);

  switch (p_event->type) {
    case QIMG_EVT_DONE:
      pthread_cond_signal(&lib2d_obj->cond);
      break;
    default:;
  }
  return IMG_SUCCESS;
}

/**
 * Function: lib2d_callback_handler
 *
 * Description: Callback handler. Registered with Component
 *     on IMG_COMP_INIT. Will be called when processing
 *     of current request is completed. If component running in
 *     async mode, this is where client will know the execution
 *     is finished for in, out frames.
 *
 * Input parameters:
 *   p_appdata - lib2d test object
 *   p_in_frame - pointer to input frame
 *   p_out_frame - pointer to output frame
 *
 * Return values:
 *   IMG_SUCCESS
 *   IMG_ERR_GENERAL
 *
 * Notes: none
 **/
int lib2d_callback_handler(void *userdata, img_frame_t *p_in_frame,
  img_frame_t *p_out_frame)
{
  mm_lib2d_obj *lib2d_obj = (mm_lib2d_obj *)userdata;
  lib2d_job_private_info *job_info = NULL;

  if (NULL == userdata) {
    LOGE("invalid event");
    return IMG_ERR_INVALID_INPUT;
  }

  // assert(p_in_frame->private_data == p_out_frame->private_data);

  job_info = (lib2d_job_private_info *)p_in_frame->private_data;
  if (job_info->lib2d_client_cb != NULL) {
    job_info->lib2d_client_cb(job_info->userdata, job_info->jobid);
  }

  free(p_in_frame->private_data);
  free(p_in_frame);
  free(p_out_frame);

  return IMG_SUCCESS;
}

/**
 * Function: lib2d_fill_img_frame
 *
 * Description: Setup img_frame_t for given buffer
 *
 * Input parameters:
 *   p_frame - pointer to img_frame_t that needs to be setup
 *   lib2d_buffer - pointer to input buffer
 *   jobid - job id
 *
 * Return values:
 *   MM_LIB2D_SUCCESS
 *   MM_LIB2D_ERR_GENERAL
 *
 * Notes: none
 **/
lib2d_error lib2d_fill_img_frame(img_frame_t *p_frame,
  mm_lib2d_buffer* lib2d_buffer, int jobid)
{
  // use job id for now
  p_frame->frame_cnt = jobid;
  p_frame->idx       = jobid;
  p_frame->frame_id  = jobid;

  if (lib2d_buffer->buffer_type == MM_LIB2D_BUFFER_TYPE_RGB) {
    mm_lib2d_rgb_buffer *rgb_buffer = &lib2d_buffer->rgb_buffer;

    p_frame->info.num_planes = 1;
    p_frame->info.width      = rgb_buffer->width;
    p_frame->info.height     = rgb_buffer->height;

    p_frame->frame[0].plane_cnt = 1;
    p_frame->frame[0].plane[0].plane_type = PLANE_ARGB;
    p_frame->frame[0].plane[0].addr       = rgb_buffer->buffer;
    p_frame->frame[0].plane[0].stride     = rgb_buffer->stride;
    p_frame->frame[0].plane[0].length     = (rgb_buffer->stride *
                                             rgb_buffer->height);
    p_frame->frame[0].plane[0].fd         = rgb_buffer->fd;
    p_frame->frame[0].plane[0].height     = rgb_buffer->height;
    p_frame->frame[0].plane[0].width      = rgb_buffer->width;
    p_frame->frame[0].plane[0].offset     = 0;
    p_frame->frame[0].plane[0].scanline   = rgb_buffer->height;
  } else if (lib2d_buffer->buffer_type == MM_LIB2D_BUFFER_TYPE_YUV) {
    mm_lib2d_yuv_buffer *yuv_buffer = &lib2d_buffer->yuv_buffer;

    p_frame->info.num_planes = 2;
    p_frame->info.width      = yuv_buffer->width;
    p_frame->info.height     = yuv_buffer->height;

    p_frame->frame[0].plane_cnt = 2;
    p_frame->frame[0].plane[0].plane_type = PLANE_Y;
    p_frame->frame[0].plane[0].addr       = yuv_buffer->plane0;
    p_frame->frame[0].plane[0].stride     = yuv_buffer->stride0;
    p_frame->frame[0].plane[0].length     = (yuv_buffer->stride0 *
                                             yuv_buffer->height);
    p_frame->frame[0].plane[0].fd         = yuv_buffer->fd;
    p_frame->frame[0].plane[0].height     = yuv_buffer->height;
    p_frame->frame[0].plane[0].width      = yuv_buffer->width;
    p_frame->frame[0].plane[0].offset     = 0;
    p_frame->frame[0].plane[0].scanline   = yuv_buffer->height;

    if (yuv_buffer->format == CAM_FORMAT_YUV_420_NV12) {
      p_frame->frame[0].plane[1].plane_type = PLANE_CB_CR;
    } else if(yuv_buffer->format == CAM_FORMAT_YUV_420_NV21) {
      p_frame->frame[0].plane[1].plane_type = PLANE_CR_CB;
    }
    p_frame->frame[0].plane[1].addr       = yuv_buffer->plane1;
    p_frame->frame[0].plane[1].stride     = yuv_buffer->stride1;
    p_frame->frame[0].plane[1].length     = (yuv_buffer->stride1 *
                                             yuv_buffer->height / 2);
    p_frame->frame[0].plane[1].fd         = yuv_buffer->fd;
    p_frame->frame[0].plane[1].height     = yuv_buffer->height;
    p_frame->frame[0].plane[1].width      = yuv_buffer->width;
    p_frame->frame[0].plane[1].offset     = 0;
    p_frame->frame[0].plane[1].scanline   = yuv_buffer->height;
  } else {
    return MM_LIB2D_ERR_GENERAL;
  }

  return MM_LIB2D_SUCCESS;
}

/**
 * Function: mm_lib2d_init
 *
 * Description: Initialization function for Lib2D. src_format, dst_format
 *     are hints to the underlying component to initialize.
 *
 * Input parameters:
 *   mode - Mode (sync/async) in which App wants lib2d to run.
 *   src_format - source surface format
 *   dst_format - Destination surface format
 *   my_obj - handle that will be returned on succesful Init. App has to
 *       call other lib2d functions by passing this handle.
 *
 * Return values:
 *   MM_LIB2D_SUCCESS
 *   MM_LIB2D_ERR_MEMORY
 *   MM_LIB2D_ERR_BAD_PARAM
 *   MM_LIB2D_ERR_GENERAL
 *
 * Notes: none
 **/
lib2d_error mm_lib2d_init(lib2d_mode mode, cam_format_t src_format,
  cam_format_t dst_format, void **my_obj)
{
  int32_t              rc         = IMG_SUCCESS;
  mm_lib2d_obj        *lib2d_obj  = NULL;
  img_core_ops_t      *p_core_ops = NULL;
  img_component_ops_t *p_comp     = NULL;

  if (my_obj == NULL) {
    return MM_LIB2D_ERR_BAD_PARAM;
  }

  // validate src_format, dst_format to check whether we support these.
  // Currently support NV21 to ARGB conversions only. Others not tested.
  if ((src_format != CAM_FORMAT_YUV_420_NV21) ||
    (dst_format != CAM_FORMAT_8888_ARGB)) {
    LOGE("Formats conversion from %d to %d not supported",
        src_format, dst_format);
  }

  lib2d_obj = malloc(sizeof(mm_lib2d_obj));
  if (lib2d_obj == NULL) {
    return MM_LIB2D_ERR_MEMORY;
  }

  // Open libmmcamera_imglib
  lib2d_obj->img_lib.ptr = dlopen("libmmcamera_imglib.so", RTLD_NOW);
  if (!lib2d_obj->img_lib.ptr) {
    LOGE("ERROR: couldn't dlopen libmmcamera_imglib.so: %s",
       dlerror());
    goto FREE_LIB2D_OBJ;
  }

  /* Get function pointer for functions supported by C2D */
  *(void **)&lib2d_obj->img_lib.img_core_get_comp =
      dlsym(lib2d_obj->img_lib.ptr, "img_core_get_comp");
  *(void **)&lib2d_obj->img_lib.img_wait_for_completion =
      dlsym(lib2d_obj->img_lib.ptr, "img_wait_for_completion");

  /* Validate function pointers */
  if ((lib2d_obj->img_lib.img_core_get_comp == NULL) ||
    (lib2d_obj->img_lib.img_wait_for_completion == NULL)) {
    LOGE(" ERROR mapping symbols from libc2d2.so");
    goto FREE_LIB2D_OBJ;
  }

  p_core_ops = &lib2d_obj->core_ops;
  p_comp     = &lib2d_obj->comp;

  pthread_mutex_init(&lib2d_obj->mutex, NULL);
  pthread_cond_init(&lib2d_obj->cond, NULL);

  rc = lib2d_obj->img_lib.img_core_get_comp(IMG_COMP_LIB2D,
    "qti.lib2d", p_core_ops);
  if (rc != IMG_SUCCESS) {
    LOGE("rc %d", rc);
    goto FREE_LIB2D_OBJ;
  }

  rc = IMG_COMP_LOAD(p_core_ops, NULL);
  if (rc != IMG_SUCCESS) {
    LOGE("rc %d", rc);
    goto FREE_LIB2D_OBJ;
  }

  rc = IMG_COMP_CREATE(p_core_ops, p_comp);
  if (rc != IMG_SUCCESS) {
    LOGE("rc %d", rc);
    goto COMP_UNLOAD;
  }

  rc = IMG_COMP_INIT(p_comp, (void *)lib2d_obj, lib2d_callback_handler);
  if (rc != IMG_SUCCESS) {
    LOGE("rc %d", rc);
    goto COMP_UNLOAD;
  }

  rc = IMG_COMP_SET_CB(p_comp, lib2d_event_handler);
  if (rc != IMG_SUCCESS) {
    LOGE("rc %d", rc);
    goto COMP_DEINIT;
  }

  lib2d_obj->lib2d_mode = mode;
  img_comp_mode_t comp_mode;
  if (lib2d_obj->lib2d_mode == MM_LIB2D_SYNC_MODE) {
    comp_mode = IMG_SYNC_MODE;
  } else {
    comp_mode = IMG_ASYNC_MODE;
  }

  // Set source format
  rc = IMG_COMP_SET_PARAM(p_comp, QLIB2D_SOURCE_FORMAT, (void *)&src_format);
  if (rc != IMG_SUCCESS) {
    LOGE("rc %d", rc);
    goto COMP_DEINIT;
  }

  // Set destination format
  rc = IMG_COMP_SET_PARAM(p_comp, QLIB2D_DESTINATION_FORMAT,
    (void *)&dst_format);
  if (rc != IMG_SUCCESS) {
    LOGE("rc %d", rc);
    goto COMP_DEINIT;
  }

  // Try setting the required mode.
  rc = IMG_COMP_SET_PARAM(p_comp, QIMG_PARAM_MODE, (void *)&comp_mode);
  if (rc != IMG_SUCCESS) {
    LOGE("rc %d", rc);
    goto COMP_DEINIT;
  }

  // Get the mode to make sure whether the component is really running
  // in the mode what we set.
  rc = IMG_COMP_GET_PARAM(p_comp, QIMG_PARAM_MODE,
    (void *)&lib2d_obj->comp_mode);
  if (rc != IMG_SUCCESS) {
    LOGE("rc %d", rc);
    goto COMP_DEINIT;
  }

  if (comp_mode != lib2d_obj->comp_mode) {
    LOGD("Component is running in %d mode",
      lib2d_obj->comp_mode);
  }

  *my_obj = (void *)lib2d_obj;

  return MM_LIB2D_SUCCESS;

COMP_DEINIT :
  rc = IMG_COMP_DEINIT(p_comp);
  if (rc != IMG_SUCCESS) {
    LOGE("rc %d", rc);
    return MM_LIB2D_ERR_GENERAL;
  }

COMP_UNLOAD :
  rc = IMG_COMP_UNLOAD(p_core_ops);
  if (rc != IMG_SUCCESS) {
    LOGE("rc %d", rc);
    return MM_LIB2D_ERR_GENERAL;
  }

FREE_LIB2D_OBJ :
  free(lib2d_obj);
  return MM_LIB2D_ERR_GENERAL;
}

/**
 * Function: mm_lib2d_deinit
 *
 * Description: De-Initialization function for Lib2D
 *
 * Input parameters:
 *   lib2d_obj_handle - handle tto the lib2d object
 *
 * Return values:
 *   MM_LIB2D_SUCCESS
 *   MM_LIB2D_ERR_GENERAL
 *
 * Notes: none
 **/
lib2d_error mm_lib2d_deinit(void *lib2d_obj_handle)
{
  mm_lib2d_obj        *lib2d_obj  = (mm_lib2d_obj *)lib2d_obj_handle;
  int                  rc         = IMG_SUCCESS;
  img_core_ops_t      *p_core_ops = &lib2d_obj->core_ops;
  img_component_ops_t *p_comp     = &lib2d_obj->comp;

  rc = IMG_COMP_DEINIT(p_comp);
  if (rc != IMG_SUCCESS) {
    LOGE("rc %d", rc);
    return MM_LIB2D_ERR_GENERAL;
  }

  rc = IMG_COMP_UNLOAD(p_core_ops);
  if (rc != IMG_SUCCESS) {
    LOGE("rc %d", rc);
    return MM_LIB2D_ERR_GENERAL;
  }

  dlclose(lib2d_obj->img_lib.ptr);
  free(lib2d_obj);

  return MM_LIB2D_SUCCESS;
}

/**
 * Function: mm_lib2d_start_job
 *
 * Description: Start executing the job
 *
 * Input parameters:
 *   lib2d_obj_handle - handle tto the lib2d object
 *   src_buffer - pointer to the source buffer
 *   dst_buffer - pointer to the destination buffer
 *   jobid - job id of this request
 *   userdata - userdata that will be pass through callback function
 *   cb - callback function that will be called on completion of this job
 *
 * Return values:
 *   MM_LIB2D_SUCCESS
 *   MM_LIB2D_ERR_MEMORY
 *   MM_LIB2D_ERR_GENERAL
 *
 * Notes: none
 **/
lib2d_error mm_lib2d_start_job(void *lib2d_obj_handle,
  mm_lib2d_buffer* src_buffer, mm_lib2d_buffer* dst_buffer,
  int jobid, void *userdata, lib2d_client_cb cb)
{
  mm_lib2d_obj        *lib2d_obj  = (mm_lib2d_obj *)lib2d_obj_handle;
  int                  rc         = IMG_SUCCESS;
  img_core_ops_t      *p_core_ops = &lib2d_obj->core_ops;
  img_component_ops_t *p_comp     = &lib2d_obj->comp;

  img_frame_t *p_in_frame = malloc(sizeof(img_frame_t));
  if (p_in_frame == NULL) {
    return MM_LIB2D_ERR_MEMORY;
  }

  img_frame_t *p_out_frame = malloc(sizeof(img_frame_t));
  if (p_out_frame == NULL) {
    free(p_in_frame);
    return MM_LIB2D_ERR_MEMORY;
  }

  lib2d_job_private_info *p_job_info = malloc(sizeof(lib2d_job_private_info));
  if (p_out_frame == NULL) {
    free(p_in_frame);
    free(p_out_frame);
    return MM_LIB2D_ERR_MEMORY;
  }

  memset(p_in_frame,  0x0, sizeof(img_frame_t));
  memset(p_out_frame, 0x0, sizeof(img_frame_t));
  memset(p_job_info,  0x0, sizeof(lib2d_job_private_info));

  // Fill up job info private data structure that can be used in callback to
  // inform back to the client.
  p_job_info->jobid           = jobid;
  p_job_info->userdata        = userdata;
  p_job_info->lib2d_client_cb = cb;

  p_in_frame->private_data  = (void *)p_job_info;
  p_out_frame->private_data = (void *)p_job_info;

  // convert the input info into component understandble data structures

  // Prepare Input, output frames
  lib2d_fill_img_frame(p_in_frame, src_buffer, jobid);
  lib2d_fill_img_frame(p_out_frame, dst_buffer, jobid);

  // call set_param to set the source, destination formats

  rc = IMG_COMP_Q_BUF(p_comp, p_in_frame, IMG_IN);
  if (rc != IMG_SUCCESS) {
    LOGE("rc %d", rc);
    goto ERROR;
  }

  rc = IMG_COMP_Q_BUF(p_comp, p_out_frame, IMG_OUT);
  if (rc != IMG_SUCCESS) {
    LOGE("rc %d", rc);
    goto ERROR;
  }

  rc = IMG_COMP_START(p_comp, NULL);
  if (rc != IMG_SUCCESS) {
    LOGE("rc %d", rc);
    goto ERROR;
  }

  if (lib2d_obj->lib2d_mode == MM_LIB2D_SYNC_MODE) {
    if (lib2d_obj->comp_mode == IMG_ASYNC_MODE) {
      LOGD("before wait rc %d", rc);
      rc = lib2d_obj->img_lib.img_wait_for_completion(&lib2d_obj->cond,
        &lib2d_obj->mutex, 10000);
      if (rc != IMG_SUCCESS) {
        LOGE("rc %d", rc);
        goto ERROR;
      }
    }
  }

  rc = IMG_COMP_ABORT(p_comp, NULL);
  if (IMG_ERROR(rc)) {
    LOGE("comp abort failed %d", rc);
    return rc;
  }

  return MM_LIB2D_SUCCESS;
ERROR:
  free(p_in_frame);
  free(p_out_frame);
  free(p_job_info);

  return MM_LIB2D_ERR_GENERAL;
}