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 #include "img_meta.h"
51 
52 /** lib2d_job_private_info
53  * @jobid: Job id of this process request
54  * @userdata: Client userdata that will be passed on callback
55  * @lib2d_client_cb: Application's callback function pointer
56  *     which will be called upon completion of current job.
57 **/
58 typedef struct lib2d_job_private_info_t {
59   int   jobid;
60   void *userdata;
61   lib2d_error (*lib2d_client_cb) (void *userdata, int jobid);
62 } lib2d_job_private_info;
63 
64 /** img_lib_t
65  * @ptr: handle to imglib library
66  * @img_core_get_comp: function pointer for img_core_get_comp
67  * @img_wait_for_completion: function pointer for img_wait_for_completion
68 **/
69 typedef struct {
70   void *ptr;
71   int (*img_core_get_comp) (img_comp_role_t role, char *name,
72     img_core_ops_t *p_ops);
73   int (*img_wait_for_completion) (pthread_cond_t *p_cond,
74     pthread_mutex_t *p_mutex, int32_t ms);
75 } img_lib_t;
76 
77 /** mm_lib2d_obj
78  * @core_ops: image core ops structure handle
79  * @comp: component structure handle
80  * @comp_mode: underlying component mode
81  * @lib2d_mode: lib2d mode requested by client
82  * @img_lib: imglib library, function ptrs handle
83  * @mutex: lib2d mutex used for synchronization
84  * @cond: librd cond used for synchronization
85 **/
86 typedef struct mm_lib2d_obj_t {
87   img_core_ops_t      core_ops;
88   img_component_ops_t comp;
89   img_comp_mode_t     comp_mode;
90   lib2d_mode          lib2d_mode;
91   img_lib_t           img_lib;
92   pthread_mutex_t     mutex;
93   pthread_cond_t      cond;
94 } mm_lib2d_obj;
95 
96 
97 /**
98  * Function: lib2d_event_handler
99  *
100  * Description: Event handler. All the component events
101  *     are received here.
102  *
103  * Input parameters:
104  *   p_appdata - lib2d test object
105  *   p_event - pointer to the event
106  *
107  * Return values:
108  *   IMG_SUCCESS
109  *   IMG_ERR_INVALID_INPUT
110  *
111  * Notes: none
112  **/
lib2d_event_handler(void * p_appdata,img_event_t * p_event)113 int lib2d_event_handler(void* p_appdata, img_event_t *p_event)
114 {
115   mm_lib2d_obj *lib2d_obj = (mm_lib2d_obj *)p_appdata;
116 
117   if ((NULL == p_event) || (NULL == p_appdata)) {
118     LOGE("invalid event");
119     return IMG_ERR_INVALID_INPUT;
120   }
121 
122   LOGD("type %d", p_event->type);
123 
124   switch (p_event->type) {
125     case QIMG_EVT_DONE:
126       pthread_cond_signal(&lib2d_obj->cond);
127       break;
128     default:;
129   }
130   return IMG_SUCCESS;
131 }
132 
133 /**
134  * Function: lib2d_callback_handler
135  *
136  * Description: Callback handler. Registered with Component
137  *     on IMG_COMP_INIT. Will be called when processing
138  *     of current request is completed. If component running in
139  *     async mode, this is where client will know the execution
140  *     is finished for in, out frames.
141  *
142  * Input parameters:
143  *   p_appdata - lib2d test object
144  *   p_in_frame - pointer to input frame
145  *   p_out_frame - pointer to output frame
146  *   p_meta - pointer to meta data
147  *
148  * Return values:
149  *   IMG_SUCCESS
150  *   IMG_ERR_GENERAL
151  *
152  * Notes: none
153  **/
lib2d_callback_handler(void * userdata,img_frame_t * p_in_frame,img_frame_t * p_out_frame,img_meta_t * p_meta)154 int lib2d_callback_handler(void *userdata, img_frame_t *p_in_frame,
155   img_frame_t *p_out_frame, img_meta_t *p_meta)
156 {
157   lib2d_job_private_info *job_info = NULL;
158 
159   if (NULL == userdata) {
160     LOGE("invalid event");
161     return IMG_ERR_INVALID_INPUT;
162   }
163 
164   // assert(p_in_frame->private_data == p_out_frame->private_data);
165 
166   job_info = (lib2d_job_private_info *)p_in_frame->private_data;
167   if (job_info->lib2d_client_cb != NULL) {
168     job_info->lib2d_client_cb(job_info->userdata, job_info->jobid);
169   }
170 
171   free(p_in_frame->private_data);
172   free(p_in_frame);
173   free(p_out_frame);
174   free(p_meta);
175 
176   return IMG_SUCCESS;
177 }
178 
179 /**
180  * Function: lib2d_fill_img_frame
181  *
182  * Description: Setup img_frame_t for given buffer
183  *
184  * Input parameters:
185  *   p_frame - pointer to img_frame_t that needs to be setup
186  *   lib2d_buffer - pointer to input buffer
187  *   jobid - job id
188  *
189  * Return values:
190  *   MM_LIB2D_SUCCESS
191  *   MM_LIB2D_ERR_GENERAL
192  *
193  * Notes: none
194  **/
lib2d_fill_img_frame(img_frame_t * p_frame,mm_lib2d_buffer * lib2d_buffer,int jobid)195 lib2d_error lib2d_fill_img_frame(img_frame_t *p_frame,
196   mm_lib2d_buffer* lib2d_buffer, int jobid)
197 {
198   // use job id for now
199   p_frame->frame_cnt = jobid;
200   p_frame->idx       = jobid;
201   p_frame->frame_id  = jobid;
202 
203   if (lib2d_buffer->buffer_type == MM_LIB2D_BUFFER_TYPE_RGB) {
204     mm_lib2d_rgb_buffer *rgb_buffer = &lib2d_buffer->rgb_buffer;
205 
206     p_frame->info.num_planes = 1;
207     p_frame->info.width      = rgb_buffer->width;
208     p_frame->info.height     = rgb_buffer->height;
209 
210     p_frame->frame[0].plane_cnt = 1;
211     p_frame->frame[0].plane[0].plane_type = PLANE_ARGB;
212     p_frame->frame[0].plane[0].addr       = rgb_buffer->buffer;
213     p_frame->frame[0].plane[0].stride     = rgb_buffer->stride;
214     p_frame->frame[0].plane[0].length     = (rgb_buffer->stride *
215                                              rgb_buffer->height);
216     p_frame->frame[0].plane[0].fd         = rgb_buffer->fd;
217     p_frame->frame[0].plane[0].height     = rgb_buffer->height;
218     p_frame->frame[0].plane[0].width      = rgb_buffer->width;
219     p_frame->frame[0].plane[0].offset     = 0;
220     p_frame->frame[0].plane[0].scanline   = rgb_buffer->height;
221   } else if (lib2d_buffer->buffer_type == MM_LIB2D_BUFFER_TYPE_YUV) {
222     mm_lib2d_yuv_buffer *yuv_buffer = &lib2d_buffer->yuv_buffer;
223 
224     p_frame->info.num_planes = 2;
225     p_frame->info.width      = yuv_buffer->width;
226     p_frame->info.height     = yuv_buffer->height;
227 
228     p_frame->frame[0].plane_cnt = 2;
229     p_frame->frame[0].plane[0].plane_type = PLANE_Y;
230     p_frame->frame[0].plane[0].addr       = yuv_buffer->plane0;
231     p_frame->frame[0].plane[0].stride     = yuv_buffer->stride0;
232     p_frame->frame[0].plane[0].length     = (yuv_buffer->stride0 *
233                                              yuv_buffer->height);
234     p_frame->frame[0].plane[0].fd         = yuv_buffer->fd;
235     p_frame->frame[0].plane[0].height     = yuv_buffer->height;
236     p_frame->frame[0].plane[0].width      = yuv_buffer->width;
237     p_frame->frame[0].plane[0].offset     = 0;
238     p_frame->frame[0].plane[0].scanline   = yuv_buffer->height;
239 
240     if (yuv_buffer->format == CAM_FORMAT_YUV_420_NV12) {
241       p_frame->frame[0].plane[1].plane_type = PLANE_CB_CR;
242     } else if(yuv_buffer->format == CAM_FORMAT_YUV_420_NV21) {
243       p_frame->frame[0].plane[1].plane_type = PLANE_CR_CB;
244     }
245     p_frame->frame[0].plane[1].addr       = yuv_buffer->plane1;
246     p_frame->frame[0].plane[1].stride     = yuv_buffer->stride1;
247     p_frame->frame[0].plane[1].length     = (yuv_buffer->stride1 *
248                                              yuv_buffer->height / 2);
249     p_frame->frame[0].plane[1].fd         = yuv_buffer->fd;
250     p_frame->frame[0].plane[1].height     = yuv_buffer->height;
251     p_frame->frame[0].plane[1].width      = yuv_buffer->width;
252     p_frame->frame[0].plane[1].offset     = 0;
253     p_frame->frame[0].plane[1].scanline   = yuv_buffer->height;
254   } else {
255     return MM_LIB2D_ERR_GENERAL;
256   }
257 
258   return MM_LIB2D_SUCCESS;
259 }
260 
261 /**
262  * Function: mm_lib2d_init
263  *
264  * Description: Initialization function for Lib2D. src_format, dst_format
265  *     are hints to the underlying component to initialize.
266  *
267  * Input parameters:
268  *   mode - Mode (sync/async) in which App wants lib2d to run.
269  *   src_format - source surface format
270  *   dst_format - Destination surface format
271  *   my_obj - handle that will be returned on succesful Init. App has to
272  *       call other lib2d functions by passing this handle.
273  *
274  * Return values:
275  *   MM_LIB2D_SUCCESS
276  *   MM_LIB2D_ERR_MEMORY
277  *   MM_LIB2D_ERR_BAD_PARAM
278  *   MM_LIB2D_ERR_GENERAL
279  *
280  * Notes: none
281  **/
282 
mm_lib2d_init(lib2d_mode mode,cam_format_t src_format,cam_format_t dst_format,void ** my_obj)283 lib2d_error mm_lib2d_init(lib2d_mode mode, cam_format_t src_format,
284   cam_format_t dst_format, void **my_obj)
285 {
286   int32_t              rc         = IMG_SUCCESS;
287   mm_lib2d_obj        *lib2d_obj  = NULL;
288   img_core_ops_t      *p_core_ops = NULL;
289   img_component_ops_t *p_comp     = NULL;
290 
291   if (my_obj == NULL) {
292     return MM_LIB2D_ERR_BAD_PARAM;
293   }
294 
295   // validate src_format, dst_format to check whether we support these.
296   // Currently support NV21 to ARGB conversions only. Others not tested.
297   if ((src_format != CAM_FORMAT_YUV_420_NV21) ||
298     (dst_format != CAM_FORMAT_8888_ARGB)) {
299     LOGE("Formats conversion from %d to %d not supported",
300         src_format, dst_format);
301   }
302 
303   lib2d_obj = malloc(sizeof(mm_lib2d_obj));
304   if (lib2d_obj == NULL) {
305     return MM_LIB2D_ERR_MEMORY;
306   }
307 
308   // Open libmmcamera_imglib
309   lib2d_obj->img_lib.ptr = dlopen("libmmcamera_imglib.so", RTLD_NOW);
310   if (!lib2d_obj->img_lib.ptr) {
311     LOGE("ERROR: couldn't dlopen libmmcamera_imglib.so: %s",
312        dlerror());
313     goto FREE_LIB2D_OBJ;
314   }
315 
316   /* Get function pointer for functions supported by C2D */
317   *(void **)&lib2d_obj->img_lib.img_core_get_comp =
318       dlsym(lib2d_obj->img_lib.ptr, "img_core_get_comp");
319   *(void **)&lib2d_obj->img_lib.img_wait_for_completion =
320       dlsym(lib2d_obj->img_lib.ptr, "img_wait_for_completion");
321 
322   /* Validate function pointers */
323   if ((lib2d_obj->img_lib.img_core_get_comp == NULL) ||
324     (lib2d_obj->img_lib.img_wait_for_completion == NULL)) {
325     LOGE(" ERROR mapping symbols from libc2d2.so");
326     goto FREE_LIB2D_OBJ;
327   }
328 
329   p_core_ops = &lib2d_obj->core_ops;
330   p_comp     = &lib2d_obj->comp;
331 
332   pthread_mutex_init(&lib2d_obj->mutex, NULL);
333   pthread_cond_init(&lib2d_obj->cond, NULL);
334 
335   rc = lib2d_obj->img_lib.img_core_get_comp(IMG_COMP_LIB2D,
336     "qti.lib2d", p_core_ops);
337   if (rc != IMG_SUCCESS) {
338     LOGE("rc %d", rc);
339     goto FREE_LIB2D_OBJ;
340   }
341 
342   rc = IMG_COMP_LOAD(p_core_ops, NULL);
343   if (rc != IMG_SUCCESS) {
344     LOGE("rc %d", rc);
345     goto FREE_LIB2D_OBJ;
346   }
347 
348   rc = IMG_COMP_CREATE(p_core_ops, p_comp);
349   if (rc != IMG_SUCCESS) {
350     LOGE("rc %d", rc);
351     goto COMP_UNLOAD;
352   }
353 
354   rc = IMG_COMP_INIT(p_comp, (void *)lib2d_obj, lib2d_callback_handler);
355   if (rc != IMG_SUCCESS) {
356     LOGE("rc %d", rc);
357     goto COMP_UNLOAD;
358   }
359 
360   rc = IMG_COMP_SET_CB(p_comp, lib2d_event_handler);
361   if (rc != IMG_SUCCESS) {
362     LOGE("rc %d", rc);
363     goto COMP_DEINIT;
364   }
365 
366   lib2d_obj->lib2d_mode = mode;
367   img_comp_mode_t comp_mode;
368   if (lib2d_obj->lib2d_mode == MM_LIB2D_SYNC_MODE) {
369     comp_mode = IMG_SYNC_MODE;
370   } else {
371     comp_mode = IMG_ASYNC_MODE;
372   }
373 
374   // Set source format
375   rc = IMG_COMP_SET_PARAM(p_comp, QLIB2D_SOURCE_FORMAT, (void *)&src_format);
376   if (rc != IMG_SUCCESS) {
377     LOGE("rc %d", rc);
378     goto COMP_DEINIT;
379   }
380 
381   // Set destination format
382   rc = IMG_COMP_SET_PARAM(p_comp, QLIB2D_DESTINATION_FORMAT,
383     (void *)&dst_format);
384   if (rc != IMG_SUCCESS) {
385     LOGE("rc %d", rc);
386     goto COMP_DEINIT;
387   }
388 
389   // Try setting the required mode.
390   rc = IMG_COMP_SET_PARAM(p_comp, QIMG_PARAM_MODE, (void *)&comp_mode);
391   if (rc != IMG_SUCCESS) {
392     LOGE("rc %d", rc);
393     goto COMP_DEINIT;
394   }
395 
396   // Get the mode to make sure whether the component is really running
397   // in the mode what we set.
398   rc = IMG_COMP_GET_PARAM(p_comp, QIMG_PARAM_MODE,
399     (void *)&lib2d_obj->comp_mode);
400   if (rc != IMG_SUCCESS) {
401     LOGE("rc %d", rc);
402     goto COMP_DEINIT;
403   }
404 
405   if (comp_mode != lib2d_obj->comp_mode) {
406     LOGD("Component is running in %d mode",
407       lib2d_obj->comp_mode);
408   }
409 
410   *my_obj = (void *)lib2d_obj;
411 
412   return MM_LIB2D_SUCCESS;
413 
414 COMP_DEINIT :
415   rc = IMG_COMP_DEINIT(p_comp);
416   if (rc != IMG_SUCCESS) {
417     LOGE("rc %d", rc);
418     return MM_LIB2D_ERR_GENERAL;
419   }
420 
421 COMP_UNLOAD :
422   rc = IMG_COMP_UNLOAD(p_core_ops);
423   if (rc != IMG_SUCCESS) {
424     LOGE("rc %d", rc);
425     return MM_LIB2D_ERR_GENERAL;
426   }
427 
428 FREE_LIB2D_OBJ :
429   free(lib2d_obj);
430   return MM_LIB2D_ERR_GENERAL;
431 }
432 
433 /**
434  * Function: mm_lib2d_deinit
435  *
436  * Description: De-Initialization function for Lib2D
437  *
438  * Input parameters:
439  *   lib2d_obj_handle - handle tto the lib2d object
440  *
441  * Return values:
442  *   MM_LIB2D_SUCCESS
443  *   MM_LIB2D_ERR_GENERAL
444  *
445  * Notes: none
446  **/
mm_lib2d_deinit(void * lib2d_obj_handle)447 lib2d_error mm_lib2d_deinit(void *lib2d_obj_handle)
448 {
449   mm_lib2d_obj        *lib2d_obj  = (mm_lib2d_obj *)lib2d_obj_handle;
450   int                  rc         = IMG_SUCCESS;
451   img_core_ops_t      *p_core_ops = &lib2d_obj->core_ops;
452   img_component_ops_t *p_comp     = &lib2d_obj->comp;
453 
454   rc = IMG_COMP_DEINIT(p_comp);
455   if (rc != IMG_SUCCESS) {
456     LOGE("rc %d", rc);
457     return MM_LIB2D_ERR_GENERAL;
458   }
459 
460   rc = IMG_COMP_UNLOAD(p_core_ops);
461   if (rc != IMG_SUCCESS) {
462     LOGE("rc %d", rc);
463     return MM_LIB2D_ERR_GENERAL;
464   }
465 
466   dlclose(lib2d_obj->img_lib.ptr);
467   free(lib2d_obj);
468 
469   return MM_LIB2D_SUCCESS;
470 }
471 
472 /**
473  * Function: mm_lib2d_start_job
474  *
475  * Description: Start executing the job
476  *
477  * Input parameters:
478  *   lib2d_obj_handle - handle tto the lib2d object
479  *   src_buffer - pointer to the source buffer
480  *   dst_buffer - pointer to the destination buffer
481  *   jobid - job id of this request
482  *   userdata - userdata that will be pass through callback function
483  *   cb - callback function that will be called on completion of this job
484  *   rotation - rotation to be applied
485  *
486  * Return values:
487  *   MM_LIB2D_SUCCESS
488  *   MM_LIB2D_ERR_MEMORY
489  *   MM_LIB2D_ERR_GENERAL
490  *
491  * Notes: none
492  **/
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,uint32_t rotation)493 lib2d_error mm_lib2d_start_job(void *lib2d_obj_handle,
494   mm_lib2d_buffer* src_buffer, mm_lib2d_buffer* dst_buffer,
495   int jobid, void *userdata, lib2d_client_cb cb, uint32_t rotation)
496 {
497   mm_lib2d_obj        *lib2d_obj  = (mm_lib2d_obj *)lib2d_obj_handle;
498   int                  rc         = IMG_SUCCESS;
499   img_component_ops_t *p_comp     = &lib2d_obj->comp;
500 
501   img_frame_t *p_in_frame = malloc(sizeof(img_frame_t));
502   if (p_in_frame == NULL) {
503     return MM_LIB2D_ERR_MEMORY;
504   }
505 
506   img_frame_t *p_out_frame = malloc(sizeof(img_frame_t));
507   if (p_out_frame == NULL) {
508     free(p_in_frame);
509     return MM_LIB2D_ERR_MEMORY;
510   }
511 
512   img_meta_t *p_meta = malloc(sizeof(img_meta_t));
513   if (p_meta == NULL) {
514     free(p_in_frame);
515     free(p_out_frame);
516     return MM_LIB2D_ERR_MEMORY;
517   }
518 
519   lib2d_job_private_info *p_job_info = malloc(sizeof(lib2d_job_private_info));
520   if (p_out_frame == NULL) {
521     free(p_in_frame);
522     free(p_out_frame);
523     free(p_meta);
524     return MM_LIB2D_ERR_MEMORY;
525   }
526 
527   memset(p_in_frame,  0x0, sizeof(img_frame_t));
528   memset(p_out_frame, 0x0, sizeof(img_frame_t));
529   memset(p_meta, 0x0, sizeof(img_meta_t));
530   memset(p_job_info,  0x0, sizeof(lib2d_job_private_info));
531 
532   // Fill up job info private data structure that can be used in callback to
533   // inform back to the client.
534   p_job_info->jobid           = jobid;
535   p_job_info->userdata        = userdata;
536   p_job_info->lib2d_client_cb = cb;
537 
538   p_in_frame->private_data  = (void *)p_job_info;
539   p_out_frame->private_data = (void *)p_job_info;
540 
541   // convert the input info into component understandble data structures
542 
543   // Prepare Input, output frames
544   lib2d_fill_img_frame(p_in_frame, src_buffer, jobid);
545   lib2d_fill_img_frame(p_out_frame, dst_buffer, jobid);
546 
547   p_meta->frame_id = jobid;
548   p_meta->rotation.device_rotation = (int32_t)rotation;
549   p_meta->rotation.frame_rotation = (int32_t)rotation;
550 
551   // call set_param to set the source, destination formats
552 
553   rc = IMG_COMP_Q_BUF(p_comp, p_in_frame, IMG_IN);
554   if (rc != IMG_SUCCESS) {
555     LOGE("rc %d", rc);
556     goto ERROR;
557   }
558 
559   rc = IMG_COMP_Q_BUF(p_comp, p_out_frame, IMG_OUT);
560   if (rc != IMG_SUCCESS) {
561     LOGE("rc %d", rc);
562     goto ERROR;
563   }
564 
565   rc = IMG_COMP_Q_META_BUF(p_comp, p_meta);
566   if (rc != IMG_SUCCESS) {
567     LOGE("rc %d", rc);
568     goto ERROR;
569   }
570 
571   rc = IMG_COMP_START(p_comp, NULL);
572   if (rc != IMG_SUCCESS) {
573     LOGE("rc %d", rc);
574     goto ERROR;
575   }
576 
577   if (lib2d_obj->lib2d_mode == MM_LIB2D_SYNC_MODE) {
578     if (lib2d_obj->comp_mode == IMG_ASYNC_MODE) {
579       LOGD("before wait rc %d", rc);
580       rc = lib2d_obj->img_lib.img_wait_for_completion(&lib2d_obj->cond,
581         &lib2d_obj->mutex, 10000);
582       if (rc != IMG_SUCCESS) {
583         LOGE("rc %d", rc);
584         goto ERROR;
585       }
586     }
587   }
588 
589   rc = IMG_COMP_ABORT(p_comp, NULL);
590   if (IMG_ERROR(rc)) {
591     LOGE("comp abort failed %d", rc);
592     return rc;
593   }
594 
595   return MM_LIB2D_SUCCESS;
596 ERROR:
597   free(p_in_frame);
598   free(p_out_frame);
599   free(p_meta);
600   free(p_job_info);
601 
602   return MM_LIB2D_ERR_GENERAL;
603 }
604 
605