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  **/
lib2d_event_handler(void * p_appdata,img_event_t * p_event)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  **/
lib2d_callback_handler(void * userdata,img_frame_t * p_in_frame,img_frame_t * p_out_frame)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  **/
lib2d_fill_img_frame(img_frame_t * p_frame,mm_lib2d_buffer * lib2d_buffer,int jobid)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  **/
mm_lib2d_init(lib2d_mode mode,cam_format_t src_format,cam_format_t dst_format,void ** my_obj)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  **/
mm_lib2d_deinit(void * lib2d_obj_handle)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  **/
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)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