Home | History | Annotate | Download | only in src
      1 /* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
      2  *
      3  * Redistribution and use in source and binary forms, with or without
      4  * modification, are permitted provided that the following conditions are
      5  * met:
      6  *     * Redistributions of source code must retain the above copyright
      7  *       notice, this list of conditions and the following disclaimer.
      8  *     * Redistributions in binary form must reproduce the above
      9  *       copyright notice, this list of conditions and the following
     10  *       disclaimer in the documentation and/or other materials provided
     11  *       with the distribution.
     12  *     * Neither the name of The Linux Foundation nor the names of its
     13  *       contributors may be used to endorse or promote products derived
     14  *       from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     23  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     25  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     26  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  *
     28  */
     29 
     30 // To remove
     31 #include <utils/Log.h>
     32 
     33 // System dependencies
     34 #include <errno.h>
     35 #include <fcntl.h>
     36 #include <poll.h>
     37 #include <pthread.h>
     38 #include <sys/ioctl.h>
     39 #include <sys/prctl.h>
     40 #include <sys/stat.h>
     41 #include <sys/types.h>
     42 
     43 // Camera dependencies
     44 #include "img_common.h"
     45 #include "img_comp.h"
     46 #include "img_comp_factory.h"
     47 #include "img_buffer.h"
     48 #include "lib2d.h"
     49 #include "mm_lib2d.h"
     50 
     51 /** lib2d_job_private_info
     52  * @jobid: Job id of this process request
     53  * @userdata: Client userdata that will be passed on callback
     54  * @lib2d_client_cb: Application's callback function pointer
     55  *     which will be called upon completion of current job.
     56 **/
     57 typedef struct lib2d_job_private_info_t {
     58   int   jobid;
     59   void *userdata;
     60   lib2d_error (*lib2d_client_cb) (void *userdata, int jobid);
     61 } lib2d_job_private_info;
     62 
     63 /** img_lib_t
     64  * @ptr: handle to imglib library
     65  * @img_core_get_comp: function pointer for img_core_get_comp
     66  * @img_wait_for_completion: function pointer for img_wait_for_completion
     67 **/
     68 typedef struct {
     69   void *ptr;
     70   int (*img_core_get_comp) (img_comp_role_t role, char *name,
     71     img_core_ops_t *p_ops);
     72   int (*img_wait_for_completion) (pthread_cond_t *p_cond,
     73     pthread_mutex_t *p_mutex, int32_t ms);
     74 } img_lib_t;
     75 
     76 /** mm_lib2d_obj
     77  * @core_ops: image core ops structure handle
     78  * @comp: component structure handle
     79  * @comp_mode: underlying component mode
     80  * @lib2d_mode: lib2d mode requested by client
     81  * @img_lib: imglib library, function ptrs handle
     82  * @mutex: lib2d mutex used for synchronization
     83  * @cond: librd cond used for synchronization
     84 **/
     85 typedef struct mm_lib2d_obj_t {
     86   img_core_ops_t      core_ops;
     87   img_component_ops_t comp;
     88   img_comp_mode_t     comp_mode;
     89   lib2d_mode          lib2d_mode;
     90   img_lib_t           img_lib;
     91   pthread_mutex_t     mutex;
     92   pthread_cond_t      cond;
     93 } mm_lib2d_obj;
     94 
     95 
     96 /**
     97  * Function: lib2d_event_handler
     98  *
     99  * Description: Event handler. All the component events
    100  *     are received here.
    101  *
    102  * Input parameters:
    103  *   p_appdata - lib2d test object
    104  *   p_event - pointer to the event
    105  *
    106  * Return values:
    107  *   IMG_SUCCESS
    108  *   IMG_ERR_INVALID_INPUT
    109  *
    110  * Notes: none
    111  **/
    112 int lib2d_event_handler(void* p_appdata, img_event_t *p_event)
    113 {
    114   mm_lib2d_obj *lib2d_obj = (mm_lib2d_obj *)p_appdata;
    115 
    116   if ((NULL == p_event) || (NULL == p_appdata)) {
    117     LOGE("invalid event");
    118     return IMG_ERR_INVALID_INPUT;
    119   }
    120 
    121   LOGD("type %d", p_event->type);
    122 
    123   switch (p_event->type) {
    124     case QIMG_EVT_DONE:
    125       pthread_cond_signal(&lib2d_obj->cond);
    126       break;
    127     default:;
    128   }
    129   return IMG_SUCCESS;
    130 }
    131 
    132 /**
    133  * Function: lib2d_callback_handler
    134  *
    135  * Description: Callback handler. Registered with Component
    136  *     on IMG_COMP_INIT. Will be called when processing
    137  *     of current request is completed. If component running in
    138  *     async mode, this is where client will know the execution
    139  *     is finished for in, out frames.
    140  *
    141  * Input parameters:
    142  *   p_appdata - lib2d test object
    143  *   p_in_frame - pointer to input frame
    144  *   p_out_frame - pointer to output frame
    145  *
    146  * Return values:
    147  *   IMG_SUCCESS
    148  *   IMG_ERR_GENERAL
    149  *
    150  * Notes: none
    151  **/
    152 int lib2d_callback_handler(void *userdata, img_frame_t *p_in_frame,
    153   img_frame_t *p_out_frame)
    154 {
    155   mm_lib2d_obj *lib2d_obj = (mm_lib2d_obj *)userdata;
    156   lib2d_job_private_info *job_info = NULL;
    157 
    158   if (NULL == userdata) {
    159     LOGE("invalid event");
    160     return IMG_ERR_INVALID_INPUT;
    161   }
    162 
    163   // assert(p_in_frame->private_data == p_out_frame->private_data);
    164 
    165   job_info = (lib2d_job_private_info *)p_in_frame->private_data;
    166   if (job_info->lib2d_client_cb != NULL) {
    167     job_info->lib2d_client_cb(job_info->userdata, job_info->jobid);
    168   }
    169 
    170   free(p_in_frame->private_data);
    171   free(p_in_frame);
    172   free(p_out_frame);
    173 
    174   return IMG_SUCCESS;
    175 }
    176 
    177 /**
    178  * Function: lib2d_fill_img_frame
    179  *
    180  * Description: Setup img_frame_t for given buffer
    181  *
    182  * Input parameters:
    183  *   p_frame - pointer to img_frame_t that needs to be setup
    184  *   lib2d_buffer - pointer to input buffer
    185  *   jobid - job id
    186  *
    187  * Return values:
    188  *   MM_LIB2D_SUCCESS
    189  *   MM_LIB2D_ERR_GENERAL
    190  *
    191  * Notes: none
    192  **/
    193 lib2d_error lib2d_fill_img_frame(img_frame_t *p_frame,
    194   mm_lib2d_buffer* lib2d_buffer, int jobid)
    195 {
    196   // use job id for now
    197   p_frame->frame_cnt = jobid;
    198   p_frame->idx       = jobid;
    199   p_frame->frame_id  = jobid;
    200 
    201   if (lib2d_buffer->buffer_type == MM_LIB2D_BUFFER_TYPE_RGB) {
    202     mm_lib2d_rgb_buffer *rgb_buffer = &lib2d_buffer->rgb_buffer;
    203 
    204     p_frame->info.num_planes = 1;
    205     p_frame->info.width      = rgb_buffer->width;
    206     p_frame->info.height     = rgb_buffer->height;
    207 
    208     p_frame->frame[0].plane_cnt = 1;
    209     p_frame->frame[0].plane[0].plane_type = PLANE_ARGB;
    210     p_frame->frame[0].plane[0].addr       = rgb_buffer->buffer;
    211     p_frame->frame[0].plane[0].stride     = rgb_buffer->stride;
    212     p_frame->frame[0].plane[0].length     = (rgb_buffer->stride *
    213                                              rgb_buffer->height);
    214     p_frame->frame[0].plane[0].fd         = rgb_buffer->fd;
    215     p_frame->frame[0].plane[0].height     = rgb_buffer->height;
    216     p_frame->frame[0].plane[0].width      = rgb_buffer->width;
    217     p_frame->frame[0].plane[0].offset     = 0;
    218     p_frame->frame[0].plane[0].scanline   = rgb_buffer->height;
    219   } else if (lib2d_buffer->buffer_type == MM_LIB2D_BUFFER_TYPE_YUV) {
    220     mm_lib2d_yuv_buffer *yuv_buffer = &lib2d_buffer->yuv_buffer;
    221 
    222     p_frame->info.num_planes = 2;
    223     p_frame->info.width      = yuv_buffer->width;
    224     p_frame->info.height     = yuv_buffer->height;
    225 
    226     p_frame->frame[0].plane_cnt = 2;
    227     p_frame->frame[0].plane[0].plane_type = PLANE_Y;
    228     p_frame->frame[0].plane[0].addr       = yuv_buffer->plane0;
    229     p_frame->frame[0].plane[0].stride     = yuv_buffer->stride0;
    230     p_frame->frame[0].plane[0].length     = (yuv_buffer->stride0 *
    231                                              yuv_buffer->height);
    232     p_frame->frame[0].plane[0].fd         = yuv_buffer->fd;
    233     p_frame->frame[0].plane[0].height     = yuv_buffer->height;
    234     p_frame->frame[0].plane[0].width      = yuv_buffer->width;
    235     p_frame->frame[0].plane[0].offset     = 0;
    236     p_frame->frame[0].plane[0].scanline   = yuv_buffer->height;
    237 
    238     if (yuv_buffer->format == CAM_FORMAT_YUV_420_NV12) {
    239       p_frame->frame[0].plane[1].plane_type = PLANE_CB_CR;
    240     } else if(yuv_buffer->format == CAM_FORMAT_YUV_420_NV21) {
    241       p_frame->frame[0].plane[1].plane_type = PLANE_CR_CB;
    242     }
    243     p_frame->frame[0].plane[1].addr       = yuv_buffer->plane1;
    244     p_frame->frame[0].plane[1].stride     = yuv_buffer->stride1;
    245     p_frame->frame[0].plane[1].length     = (yuv_buffer->stride1 *
    246                                              yuv_buffer->height / 2);
    247     p_frame->frame[0].plane[1].fd         = yuv_buffer->fd;
    248     p_frame->frame[0].plane[1].height     = yuv_buffer->height;
    249     p_frame->frame[0].plane[1].width      = yuv_buffer->width;
    250     p_frame->frame[0].plane[1].offset     = 0;
    251     p_frame->frame[0].plane[1].scanline   = yuv_buffer->height;
    252   } else {
    253     return MM_LIB2D_ERR_GENERAL;
    254   }
    255 
    256   return MM_LIB2D_SUCCESS;
    257 }
    258 
    259 /**
    260  * Function: mm_lib2d_init
    261  *
    262  * Description: Initialization function for Lib2D. src_format, dst_format
    263  *     are hints to the underlying component to initialize.
    264  *
    265  * Input parameters:
    266  *   mode - Mode (sync/async) in which App wants lib2d to run.
    267  *   src_format - source surface format
    268  *   dst_format - Destination surface format
    269  *   my_obj - handle that will be returned on succesful Init. App has to
    270  *       call other lib2d functions by passing this handle.
    271  *
    272  * Return values:
    273  *   MM_LIB2D_SUCCESS
    274  *   MM_LIB2D_ERR_MEMORY
    275  *   MM_LIB2D_ERR_BAD_PARAM
    276  *   MM_LIB2D_ERR_GENERAL
    277  *
    278  * Notes: none
    279  **/
    280 lib2d_error mm_lib2d_init(lib2d_mode mode, cam_format_t src_format,
    281   cam_format_t dst_format, void **my_obj)
    282 {
    283   int32_t              rc         = IMG_SUCCESS;
    284   mm_lib2d_obj        *lib2d_obj  = NULL;
    285   img_core_ops_t      *p_core_ops = NULL;
    286   img_component_ops_t *p_comp     = NULL;
    287 
    288   if (my_obj == NULL) {
    289     return MM_LIB2D_ERR_BAD_PARAM;
    290   }
    291 
    292   // validate src_format, dst_format to check whether we support these.
    293   // Currently support NV21 to ARGB conversions only. Others not tested.
    294   if ((src_format != CAM_FORMAT_YUV_420_NV21) ||
    295     (dst_format != CAM_FORMAT_8888_ARGB)) {
    296     LOGE("Formats conversion from %d to %d not supported",
    297         src_format, dst_format);
    298   }
    299 
    300   lib2d_obj = malloc(sizeof(mm_lib2d_obj));
    301   if (lib2d_obj == NULL) {
    302     return MM_LIB2D_ERR_MEMORY;
    303   }
    304 
    305   // Open libmmcamera_imglib
    306   lib2d_obj->img_lib.ptr = dlopen("libmmcamera_imglib.so", RTLD_NOW);
    307   if (!lib2d_obj->img_lib.ptr) {
    308     LOGE("ERROR: couldn't dlopen libmmcamera_imglib.so: %s",
    309        dlerror());
    310     goto FREE_LIB2D_OBJ;
    311   }
    312 
    313   /* Get function pointer for functions supported by C2D */
    314   *(void **)&lib2d_obj->img_lib.img_core_get_comp =
    315       dlsym(lib2d_obj->img_lib.ptr, "img_core_get_comp");
    316   *(void **)&lib2d_obj->img_lib.img_wait_for_completion =
    317       dlsym(lib2d_obj->img_lib.ptr, "img_wait_for_completion");
    318 
    319   /* Validate function pointers */
    320   if ((lib2d_obj->img_lib.img_core_get_comp == NULL) ||
    321     (lib2d_obj->img_lib.img_wait_for_completion == NULL)) {
    322     LOGE(" ERROR mapping symbols from libc2d2.so");
    323     goto FREE_LIB2D_OBJ;
    324   }
    325 
    326   p_core_ops = &lib2d_obj->core_ops;
    327   p_comp     = &lib2d_obj->comp;
    328 
    329   pthread_mutex_init(&lib2d_obj->mutex, NULL);
    330   pthread_cond_init(&lib2d_obj->cond, NULL);
    331 
    332   rc = lib2d_obj->img_lib.img_core_get_comp(IMG_COMP_LIB2D,
    333     "qti.lib2d", p_core_ops);
    334   if (rc != IMG_SUCCESS) {
    335     LOGE("rc %d", rc);
    336     goto FREE_LIB2D_OBJ;
    337   }
    338 
    339   rc = IMG_COMP_LOAD(p_core_ops, NULL);
    340   if (rc != IMG_SUCCESS) {
    341     LOGE("rc %d", rc);
    342     goto FREE_LIB2D_OBJ;
    343   }
    344 
    345   rc = IMG_COMP_CREATE(p_core_ops, p_comp);
    346   if (rc != IMG_SUCCESS) {
    347     LOGE("rc %d", rc);
    348     goto COMP_UNLOAD;
    349   }
    350 
    351   rc = IMG_COMP_INIT(p_comp, (void *)lib2d_obj, lib2d_callback_handler);
    352   if (rc != IMG_SUCCESS) {
    353     LOGE("rc %d", rc);
    354     goto COMP_UNLOAD;
    355   }
    356 
    357   rc = IMG_COMP_SET_CB(p_comp, lib2d_event_handler);
    358   if (rc != IMG_SUCCESS) {
    359     LOGE("rc %d", rc);
    360     goto COMP_DEINIT;
    361   }
    362 
    363   lib2d_obj->lib2d_mode = mode;
    364   img_comp_mode_t comp_mode;
    365   if (lib2d_obj->lib2d_mode == MM_LIB2D_SYNC_MODE) {
    366     comp_mode = IMG_SYNC_MODE;
    367   } else {
    368     comp_mode = IMG_ASYNC_MODE;
    369   }
    370 
    371   // Set source format
    372   rc = IMG_COMP_SET_PARAM(p_comp, QLIB2D_SOURCE_FORMAT, (void *)&src_format);
    373   if (rc != IMG_SUCCESS) {
    374     LOGE("rc %d", rc);
    375     goto COMP_DEINIT;
    376   }
    377 
    378   // Set destination format
    379   rc = IMG_COMP_SET_PARAM(p_comp, QLIB2D_DESTINATION_FORMAT,
    380     (void *)&dst_format);
    381   if (rc != IMG_SUCCESS) {
    382     LOGE("rc %d", rc);
    383     goto COMP_DEINIT;
    384   }
    385 
    386   // Try setting the required mode.
    387   rc = IMG_COMP_SET_PARAM(p_comp, QIMG_PARAM_MODE, (void *)&comp_mode);
    388   if (rc != IMG_SUCCESS) {
    389     LOGE("rc %d", rc);
    390     goto COMP_DEINIT;
    391   }
    392 
    393   // Get the mode to make sure whether the component is really running
    394   // in the mode what we set.
    395   rc = IMG_COMP_GET_PARAM(p_comp, QIMG_PARAM_MODE,
    396     (void *)&lib2d_obj->comp_mode);
    397   if (rc != IMG_SUCCESS) {
    398     LOGE("rc %d", rc);
    399     goto COMP_DEINIT;
    400   }
    401 
    402   if (comp_mode != lib2d_obj->comp_mode) {
    403     LOGD("Component is running in %d mode",
    404       lib2d_obj->comp_mode);
    405   }
    406 
    407   *my_obj = (void *)lib2d_obj;
    408 
    409   return MM_LIB2D_SUCCESS;
    410 
    411 COMP_DEINIT :
    412   rc = IMG_COMP_DEINIT(p_comp);
    413   if (rc != IMG_SUCCESS) {
    414     LOGE("rc %d", rc);
    415     return MM_LIB2D_ERR_GENERAL;
    416   }
    417 
    418 COMP_UNLOAD :
    419   rc = IMG_COMP_UNLOAD(p_core_ops);
    420   if (rc != IMG_SUCCESS) {
    421     LOGE("rc %d", rc);
    422     return MM_LIB2D_ERR_GENERAL;
    423   }
    424 
    425 FREE_LIB2D_OBJ :
    426   free(lib2d_obj);
    427   return MM_LIB2D_ERR_GENERAL;
    428 }
    429 
    430 /**
    431  * Function: mm_lib2d_deinit
    432  *
    433  * Description: De-Initialization function for Lib2D
    434  *
    435  * Input parameters:
    436  *   lib2d_obj_handle - handle tto the lib2d object
    437  *
    438  * Return values:
    439  *   MM_LIB2D_SUCCESS
    440  *   MM_LIB2D_ERR_GENERAL
    441  *
    442  * Notes: none
    443  **/
    444 lib2d_error mm_lib2d_deinit(void *lib2d_obj_handle)
    445 {
    446   mm_lib2d_obj        *lib2d_obj  = (mm_lib2d_obj *)lib2d_obj_handle;
    447   int                  rc         = IMG_SUCCESS;
    448   img_core_ops_t      *p_core_ops = &lib2d_obj->core_ops;
    449   img_component_ops_t *p_comp     = &lib2d_obj->comp;
    450 
    451   rc = IMG_COMP_DEINIT(p_comp);
    452   if (rc != IMG_SUCCESS) {
    453     LOGE("rc %d", rc);
    454     return MM_LIB2D_ERR_GENERAL;
    455   }
    456 
    457   rc = IMG_COMP_UNLOAD(p_core_ops);
    458   if (rc != IMG_SUCCESS) {
    459     LOGE("rc %d", rc);
    460     return MM_LIB2D_ERR_GENERAL;
    461   }
    462 
    463   dlclose(lib2d_obj->img_lib.ptr);
    464   free(lib2d_obj);
    465 
    466   return MM_LIB2D_SUCCESS;
    467 }
    468 
    469 /**
    470  * Function: mm_lib2d_start_job
    471  *
    472  * Description: Start executing the job
    473  *
    474  * Input parameters:
    475  *   lib2d_obj_handle - handle tto the lib2d object
    476  *   src_buffer - pointer to the source buffer
    477  *   dst_buffer - pointer to the destination buffer
    478  *   jobid - job id of this request
    479  *   userdata - userdata that will be pass through callback function
    480  *   cb - callback function that will be called on completion of this job
    481  *
    482  * Return values:
    483  *   MM_LIB2D_SUCCESS
    484  *   MM_LIB2D_ERR_MEMORY
    485  *   MM_LIB2D_ERR_GENERAL
    486  *
    487  * Notes: none
    488  **/
    489 lib2d_error mm_lib2d_start_job(void *lib2d_obj_handle,
    490   mm_lib2d_buffer* src_buffer, mm_lib2d_buffer* dst_buffer,
    491   int jobid, void *userdata, lib2d_client_cb cb)
    492 {
    493   mm_lib2d_obj        *lib2d_obj  = (mm_lib2d_obj *)lib2d_obj_handle;
    494   int                  rc         = IMG_SUCCESS;
    495   img_core_ops_t      *p_core_ops = &lib2d_obj->core_ops;
    496   img_component_ops_t *p_comp     = &lib2d_obj->comp;
    497 
    498   img_frame_t *p_in_frame = malloc(sizeof(img_frame_t));
    499   if (p_in_frame == NULL) {
    500     return MM_LIB2D_ERR_MEMORY;
    501   }
    502 
    503   img_frame_t *p_out_frame = malloc(sizeof(img_frame_t));
    504   if (p_out_frame == NULL) {
    505     free(p_in_frame);
    506     return MM_LIB2D_ERR_MEMORY;
    507   }
    508 
    509   lib2d_job_private_info *p_job_info = malloc(sizeof(lib2d_job_private_info));
    510   if (p_out_frame == NULL) {
    511     free(p_in_frame);
    512     free(p_out_frame);
    513     return MM_LIB2D_ERR_MEMORY;
    514   }
    515 
    516   memset(p_in_frame,  0x0, sizeof(img_frame_t));
    517   memset(p_out_frame, 0x0, sizeof(img_frame_t));
    518   memset(p_job_info,  0x0, sizeof(lib2d_job_private_info));
    519 
    520   // Fill up job info private data structure that can be used in callback to
    521   // inform back to the client.
    522   p_job_info->jobid           = jobid;
    523   p_job_info->userdata        = userdata;
    524   p_job_info->lib2d_client_cb = cb;
    525 
    526   p_in_frame->private_data  = (void *)p_job_info;
    527   p_out_frame->private_data = (void *)p_job_info;
    528 
    529   // convert the input info into component understandble data structures
    530 
    531   // Prepare Input, output frames
    532   lib2d_fill_img_frame(p_in_frame, src_buffer, jobid);
    533   lib2d_fill_img_frame(p_out_frame, dst_buffer, jobid);
    534 
    535   // call set_param to set the source, destination formats
    536 
    537   rc = IMG_COMP_Q_BUF(p_comp, p_in_frame, IMG_IN);
    538   if (rc != IMG_SUCCESS) {
    539     LOGE("rc %d", rc);
    540     goto ERROR;
    541   }
    542 
    543   rc = IMG_COMP_Q_BUF(p_comp, p_out_frame, IMG_OUT);
    544   if (rc != IMG_SUCCESS) {
    545     LOGE("rc %d", rc);
    546     goto ERROR;
    547   }
    548 
    549   rc = IMG_COMP_START(p_comp, NULL);
    550   if (rc != IMG_SUCCESS) {
    551     LOGE("rc %d", rc);
    552     goto ERROR;
    553   }
    554 
    555   if (lib2d_obj->lib2d_mode == MM_LIB2D_SYNC_MODE) {
    556     if (lib2d_obj->comp_mode == IMG_ASYNC_MODE) {
    557       LOGD("before wait rc %d", rc);
    558       rc = lib2d_obj->img_lib.img_wait_for_completion(&lib2d_obj->cond,
    559         &lib2d_obj->mutex, 10000);
    560       if (rc != IMG_SUCCESS) {
    561         LOGE("rc %d", rc);
    562         goto ERROR;
    563       }
    564     }
    565   }
    566 
    567   rc = IMG_COMP_ABORT(p_comp, NULL);
    568   if (IMG_ERROR(rc)) {
    569     LOGE("comp abort failed %d", rc);
    570     return rc;
    571   }
    572 
    573   return MM_LIB2D_SUCCESS;
    574 ERROR:
    575   free(p_in_frame);
    576   free(p_out_frame);
    577   free(p_job_info);
    578 
    579   return MM_LIB2D_ERR_GENERAL;
    580 }
    581 
    582