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