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**/
58typedef 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**/
69typedef 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**/
86typedef 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 **/
113int 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 **/
154int 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 **/
195lib2d_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
283lib2d_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
414COMP_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
421COMP_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
428FREE_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 **/
447lib2d_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 **/
493lib2d_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;
596ERROR:
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