1 /*
2 Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
3
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are
6 met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above
10 copyright notice, this list of conditions and the following
11 disclaimer in the documentation and/or other materials provided
12 with the distribution.
13 * Neither the name of Code Aurora Forum, Inc. nor the names of its
14 contributors may be used to endorse or promote products derived
15 from this software without specific prior written permission.
16
17 THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include <fcntl.h>
31 #include <stdio.h>
32 #include <stdbool.h>
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include <pthread.h>
36 #include <sys/ioctl.h>
37 struct file;
38 struct inode;
39 #include <linux/android_pmem.h>
40 #include <sys/mman.h>
41 #include <errno.h>
42 #include <sys/time.h>
43 #include <string.h>
44
45 #include <inttypes.h>
46 #include <linux/msm_mdp.h>
47 #include <linux/fb.h>
48 #include <linux/videodev2.h>
49 #include "mm_camera_dbg.h"
50 #include "QCamera_Intf.h"
51
52 #ifdef DRAW_RECTANGLES
53 extern roi_info_t camframe_roi;
54
55 #undef CAM_FRM_DRAW_RECT
56 #define CAM_FRM_DRAW_RECT
57 #endif
58
59 #ifdef CAM_FRM_DRAW_FD_RECT
60 #undef CAM_FRM_DRAW_RECT
61 #define CAM_FRM_DRAW_RECT
62 #endif
63
64 struct fb_var_screeninfo vinfo;
65 struct fb_fix_screeninfo finfo;
66 int fb_fd = 0;
67 union {
68 char dummy[sizeof(struct mdp_blit_req_list) +
69 sizeof(struct mdp_blit_req) * 1];
70 struct mdp_blit_req_list list;
71 } yuv;
72
73 static pthread_t cam_frame_fb_thread_id;
74 static int camframe_fb_exit;
75
76 static int is_camframe_fb_thread_ready;
77 USER_INPUT_DISPLAY_T input_display;
78
79 unsigned use_overlay = 0;
80 struct msmfb_overlay_data ov_front, ov_back, *ovp_front, *ovp_back;
81 struct mdp_overlay overlay, *overlayp;
82 int vid_buf_front_id, vid_buf_back_id;
83 static unsigned char please_initialize = 1;
84 int num_of_ready_frames = 0;
85
86 static pthread_cond_t sub_thread_ready_cond = PTHREAD_COND_INITIALIZER;
87 static pthread_mutex_t sub_thread_ready_mutex = PTHREAD_MUTEX_INITIALIZER;
88 pthread_cond_t camframe_fb_cond = PTHREAD_COND_INITIALIZER;
89 pthread_mutex_t camframe_fb_mutex = PTHREAD_MUTEX_INITIALIZER;
90 static void notify_camframe_fb_thread();
91
use_overlay_fb_display_driver(void)92 void use_overlay_fb_display_driver(void)
93 {
94 use_overlay = 1;
95 }
96
overlay_set_params(struct mdp_blit_req * e)97 void overlay_set_params(struct mdp_blit_req *e)
98 {
99 int result;
100
101 if (please_initialize) {
102 overlayp = &overlay;
103 ovp_front = &ov_front;
104 ovp_back = &ov_back;
105
106 overlayp->id = MSMFB_NEW_REQUEST;
107 }
108
109 overlayp->src.width = e->src.width;
110 overlayp->src.height = e->src.height;
111 overlayp->src.format = e->src.format;
112
113 overlayp->src_rect.x = e->src_rect.x;
114 overlayp->src_rect.y = e->src_rect.y;
115 overlayp->src_rect.w = e->src_rect.w;
116 overlayp->src_rect.h = e->src_rect.h;
117
118 overlayp->dst_rect.x = e->dst_rect.x;
119 overlayp->dst_rect.y = e->dst_rect.y;
120 /* ROTATOR is enabled in overlay library, swap dimensions
121 here to take care of that */
122 overlayp->dst_rect.w = e->dst_rect.h;
123 overlayp->dst_rect.h = e->dst_rect.w;
124
125 if (overlayp->dst_rect.w > 480)
126 overlayp->dst_rect.w = 480;
127 if (overlayp->dst_rect.h > 800)
128 overlayp->dst_rect.h = 800;
129
130 overlayp->z_order = 0; // FB_OVERLAY_VID_0;
131 overlayp->alpha = e->alpha;
132 overlayp->transp_mask = 0; /* 0xF81F */
133 overlayp->flags = e->flags;
134 overlayp->is_fg = 1;
135
136 if (please_initialize) {
137 CDBG("src.width %d height %d; src_rect.x %d y %d w %d h %d; dst_rect.x %d y %d w %d h %d\n",
138 overlayp->src.width, overlayp->src.height,
139 overlayp->src_rect.x, overlayp->src_rect.y, overlayp->src_rect.w, overlayp->src_rect.h,
140 overlayp->dst_rect.x, overlayp->dst_rect.y, overlayp->dst_rect.w, overlayp->dst_rect.h
141 );
142
143 result = ioctl(fb_fd, MSMFB_OVERLAY_SET, overlayp);
144 if (result < 0) {
145 CDBG("ERROR: MSMFB_OVERLAY_SET failed!, result =%d\n", result);
146 }
147 }
148
149 if (please_initialize) {
150 vid_buf_front_id = overlayp->id; /* keep return id */
151
152 ov_front.id = overlayp->id;
153 ov_back.id = overlayp->id;
154 please_initialize = 0;
155 }
156
157 return;
158 }
159
overlay_set_frame(struct msm_frame * frame)160 void overlay_set_frame(struct msm_frame *frame)
161 {
162 ov_front.data.offset = 0;
163 ov_front.data.memory_id = frame->fd;
164 return;
165 }
166
167 /*===========================================================================
168 * FUNCTION test_app_camframe_callback
169 * DESCRIPTION display frame
170 *==========================================================================*/
test_app_camframe_callback(struct msm_frame * frame)171 void test_app_camframe_callback(struct msm_frame *frame)
172 {
173 int result = 0;
174 struct mdp_blit_req *e;
175 struct timeval td1, td2;
176 struct timezone tz;
177
178 common_crop_t *crop = (common_crop_t *) (frame->cropinfo);
179
180 /* Initialize yuv structure */
181 yuv.list.count = 1;
182
183 e = &yuv.list.req[0];
184
185 e->src.width = input_display.user_input_display_width;
186 e->src.height = input_display.user_input_display_height;
187 e->src.format = MDP_Y_CRCB_H2V2;
188 e->src.offset = 0;
189 e->src.memory_id = frame->fd;
190
191 e->dst.width = vinfo.xres;
192 e->dst.height = vinfo.yres;
193 e->dst.format = MDP_RGB_565;
194 e->dst.offset = 0;
195 e->dst.memory_id = fb_fd;
196
197 e->transp_mask = 0xffffffff;
198 e->flags = 0;
199 e->alpha = 0xff;
200
201 /* Starting doing MDP Cropping */
202 if (frame->path == OUTPUT_TYPE_P) {
203
204 if (crop->in2_w != 0 || crop->in2_h != 0) {
205
206 e->src_rect.x = (crop->out2_w - crop->in2_w + 1) / 2 - 1;
207
208 e->src_rect.y = (crop->out2_h - crop->in2_h + 1) / 2 - 1;
209
210 e->src_rect.w = crop->in2_w;
211 e->src_rect.h = crop->in2_h;
212
213 CDBG("e->src_rect.x = %d\n", e->src_rect.x);
214 CDBG("e->src_rect.y = %d\n", e->src_rect.y);
215 CDBG("e->src_rect.w = %d\n", e->src_rect.w);
216 CDBG("e->src_rect.h = %d\n", e->src_rect.h);
217
218 e->dst_rect.x = 0;
219 e->dst_rect.y = 0;
220 e->dst_rect.w = input_display.user_input_display_width;
221 e->dst_rect.h = input_display.user_input_display_height;
222 } else {
223 e->src_rect.x = 0;
224 e->src_rect.y = 0;
225 e->src_rect.w = input_display.user_input_display_width;
226 e->src_rect.h = input_display.user_input_display_height;
227
228 e->dst_rect.x = 0;
229 e->dst_rect.y = 0;
230 e->dst_rect.w = input_display.user_input_display_width;
231 e->dst_rect.h = input_display.user_input_display_height;
232 }
233 if (use_overlay) overlay_set_params(e);
234 } else {
235
236 }
237
238 gettimeofday(&td1, &tz);
239
240 if (use_overlay) overlay_set_frame(frame);
241 else {
242 result = ioctl(fb_fd, MSMFB_BLIT, &yuv.list);
243 if (result < 0) {
244 CDBG("MSM_FBIOBLT failed! line=%d\n", __LINE__);
245 }
246 }
247
248 gettimeofday(&td2, &tz);
249 CDBG("Profiling: MSMFB_BLIT takes %ld microseconds\n",
250 ((td2.tv_sec - td1.tv_sec) * 1000000 + (td2.tv_usec - td1.tv_usec)));
251
252 td1 = td2;
253 notify_camframe_fb_thread();
254 /* add frame back to the free queue*/
255 //camframe_add_frame(CAM_PREVIEW_FRAME, frame);
256 }
257
notify_camframe_fb_thread()258 void notify_camframe_fb_thread()
259 {
260 pthread_mutex_lock(&camframe_fb_mutex);
261
262 num_of_ready_frames ++;
263 pthread_cond_signal(&camframe_fb_cond);
264
265 pthread_mutex_unlock(&camframe_fb_mutex);
266 }
267
268 void camframe_fb_thread_ready_signal(void);
269
camframe_fb_thread(void * data)270 void *camframe_fb_thread(void *data)
271 {
272 int result = 0;
273 static struct timeval td1, td2;
274 struct timezone tz;
275
276 #ifdef _ANDROID_
277 fb_fd = open(ANDROID_FB0, O_RDWR);
278 CDBG("%s:android dl '%s', fd=%d\n", __func__, ANDROID_FB0, fb_fd);
279 #else
280 fb_fd = open(LE_FB0, O_RDWR);
281 CDBG("%s:LE_FB0 dl, '%s', fd=%d\n", __func__, LE_FB0, fb_fd);
282 #endif
283 if (fb_fd < 0) {
284 CDBG_ERROR("cannot open framebuffer %s or %s file node\n",
285 ANDROID_FB0, LE_FB0);
286 goto fail1;
287 }
288
289 if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo) < 0) {
290 CDBG_ERROR("cannot retrieve vscreenInfo!\n");
291 goto fail;
292 }
293
294 if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &finfo) < 0) {
295 CDBG_ERROR("can't retrieve fscreenInfo!\n");
296 goto fail;
297 }
298
299 vinfo.activate = FB_ACTIVATE_VBL;
300
301 camframe_fb_thread_ready_signal();
302
303 pthread_mutex_lock(&camframe_fb_mutex);
304 while (!camframe_fb_exit) {
305 CDBG("cam_frame_fb_thread: num_of_ready_frames: %d\n", num_of_ready_frames);
306 if (num_of_ready_frames <= 0) {
307 pthread_cond_wait(&camframe_fb_cond, &camframe_fb_mutex);
308 }
309 if (num_of_ready_frames > 0) {
310 num_of_ready_frames --;
311
312 gettimeofday(&td1, &tz);
313 if (use_overlay) {
314 result = ioctl(fb_fd, MSMFB_OVERLAY_PLAY, ovp_front);
315 } else {
316 result = ioctl(fb_fd, FBIOPAN_DISPLAY, &vinfo);
317 }
318
319 gettimeofday(&td2, &tz);
320
321 CDBG("Profiling: frame timestamp after FBIO display = %ld ms\n",
322 (td2.tv_sec*1000) + (td2.tv_usec/1000));
323
324 CDBG("cam_frame_fb_thread: elapse time for FBIOPAN_DISPLAY = %ld, return = %d\n",
325 (td2.tv_sec - td1.tv_sec) * 1000000 + td2.tv_usec - td1.tv_usec, result);
326
327 if (result < 0) {
328 CDBG("DISPLAY: Failed\n");
329 }
330 }
331 }
332
333 pthread_mutex_unlock(&camframe_fb_mutex);
334
335 if (use_overlay) {
336 if (ioctl(fb_fd, MSMFB_OVERLAY_UNSET, &vid_buf_front_id)) {
337 CDBG("\nERROR! MSMFB_OVERLAY_UNSET failed! (Line %d)\n", __LINE__);
338 goto fail;
339 }
340 }
341
342 return NULL;
343
344 fail:
345 close(fb_fd);
346 fail1:
347 camframe_fb_exit = -1;
348 camframe_fb_thread_ready_signal();
349 return NULL;
350 }
351
launch_camframe_fb_thread(void)352 int launch_camframe_fb_thread(void)
353 {
354
355 camframe_fb_exit = 0;
356 is_camframe_fb_thread_ready = 0;
357 pthread_create(&cam_frame_fb_thread_id, NULL, camframe_fb_thread, NULL);
358
359 /* Waiting for launching sub thread ready signal. */
360 CDBG("launch_camframe_fb_thread(), call pthread_cond_wait\n");
361
362 pthread_mutex_lock(&sub_thread_ready_mutex);
363 if (!is_camframe_fb_thread_ready) {
364 pthread_cond_wait(&sub_thread_ready_cond, &sub_thread_ready_mutex);
365 }
366 pthread_mutex_unlock(&sub_thread_ready_mutex);
367
368 CDBG("launch_camframe_fb_thread(), call pthread_cond_wait done\n");
369 CDBG("%s:fb rc=%d\n", __func__, camframe_fb_exit);
370 return camframe_fb_exit;
371 }
372
release_camframe_fb_thread(void)373 void release_camframe_fb_thread(void)
374 {
375 camframe_fb_exit = 1;
376 please_initialize = 1;
377
378 /* Notify the camframe fb thread to wake up */
379 if (cam_frame_fb_thread_id != 0) {
380 pthread_mutex_lock(&camframe_fb_mutex);
381 pthread_cond_signal(&camframe_fb_cond);
382 pthread_mutex_unlock(&camframe_fb_mutex);
383 if (pthread_join(cam_frame_fb_thread_id, NULL) != 0) {
384 CDBG("cam_frame_fb_thread exit failure!\n");
385 }
386 close(fb_fd);
387 }
388 }
389
camframe_fb_thread_ready_signal(void)390 void camframe_fb_thread_ready_signal(void)
391 {
392 /* Send the signal to control thread to indicate that the cam frame fb
393 * ready.
394 */
395 CDBG("cam_frame_fb_thread() is ready, call pthread_cond_signal\n");
396
397 pthread_mutex_lock(&sub_thread_ready_mutex);
398 is_camframe_fb_thread_ready = 1;
399 pthread_cond_signal(&sub_thread_ready_cond);
400 pthread_mutex_unlock(&sub_thread_ready_mutex);
401
402 CDBG("cam_frame_fb_thread() is ready, call pthread_cond_signal done\n");
403 }
404
405 #ifdef CAM_FRM_DRAW_RECT
draw_rect(char * buf,int buf_w,int x,int y,int dx,int dy)406 void draw_rect(char *buf, int buf_w,
407 int x, int y, int dx, int dy)
408 {
409 int i;
410 int left = x;
411 int right = x+dx;
412 int top = y;
413 int bottom = y+dy;
414
415 for (i = left; i < right; i++) {
416 buf[top*buf_w+i] = 0xff;
417 buf[bottom*buf_w+i] = 0xff;
418 }
419 for (i = top; i < bottom; i++) {
420 buf[i*buf_w+left] = 0xff;
421 buf[i*buf_w+right] = 0xff;
422 }
423 }
424 #endif
425
draw_rectangles(struct msm_frame * newFrame)426 void draw_rectangles(struct msm_frame* newFrame)
427 {
428 struct fd_roi_t *p_fd_roi;
429 #ifdef DRAW_RECTANGLES
430 uint8_t i;
431 for (i = 0; i < camframe_roi.num_roi; i++) {
432 CDBG("%s: camframe_roi: i=%d, x=%d, y=%d, dx=%d, dy=%d\n", __func__,
433 i, camframe_roi.roi[i].x, camframe_roi.roi[i].y,
434 camframe_roi.roi[i].dx, camframe_roi.roi[i].dy);
435 draw_rect((char*)newFrame->buffer, 640,
436 camframe_roi.roi[i].x, camframe_roi.roi[i].y,
437 camframe_roi.roi[i].dx, camframe_roi.roi[i].dy);
438 }
439 #endif
440
441 #ifdef CAM_FRM_DRAW_FD_RECT
442 p_fd_roi = (struct fd_roi_t *)newFrame->roi_info.info;
443 if(p_fd_roi && p_fd_roi->rect_num > 0){
444 int i;
445 for(i =0; i < p_fd_roi->rect_num; i++)
446 {
447 draw_rect((char*)newFrame->buffer, 800,
448 p_fd_roi->faces[i].x, p_fd_roi->faces[i].y,
449 p_fd_roi->faces[i].dx, p_fd_roi->faces[i].dy);
450 }
451 }
452 #endif
453 }
454
455 /*===========================================================================
456 * FUNCTION - v4l2_render -
457 *
458 * DESCRIPTION:
459 *==========================================================================*/
v4l2_render(int frame_fd,struct v4l2_buffer * vb,struct v4l2_crop * crop)460 int v4l2_render(int frame_fd, struct v4l2_buffer *vb, struct v4l2_crop *crop)
461 {
462 struct mdp_blit_req *e;
463 /* Initialize yuv structure */
464 yuv.list.count = 1;
465 e = &yuv.list.req[0];
466
467 e->src.width = input_display.user_input_display_width;
468 e->src.height = input_display.user_input_display_height;
469 e->src.format = MDP_Y_CBCR_H2V2;
470 e->src.offset = 0;
471 e->src.memory_id = frame_fd;
472
473 e->dst.width = vinfo.xres;
474 e->dst.height = vinfo.yres;
475 e->dst.format = MDP_RGB_565;
476 e->dst.offset = 0;
477 e->dst.memory_id = fb_fd;
478
479 e->transp_mask = 0xffffffff;
480 e->flags = 0;
481 e->alpha = 0xff;
482
483 if (crop != NULL && (crop->c.width != 0 || crop->c.height != 0)) {
484 e->src_rect.x = crop->c.left;
485 e->src_rect.y = crop->c.top;
486 e->src_rect.w = crop->c.width;
487 e->src_rect.h = crop->c.height;
488
489 e->dst_rect.x = 0;
490 e->dst_rect.y = 0;
491 e->dst_rect.w = input_display.user_input_display_width;
492 e->dst_rect.h = input_display.user_input_display_height;
493 } else {
494 e->dst_rect.x = 0;
495 e->dst_rect.y = 0;
496 e->dst_rect.w = input_display.user_input_display_width;
497 e->dst_rect.h = input_display.user_input_display_height;
498
499 e->src_rect.x = 0;
500 e->src_rect.y = 0;
501 e->src_rect.w = input_display.user_input_display_width;
502 e->src_rect.h = input_display.user_input_display_height;
503 }
504 overlay_set_params(e);
505 ov_front.data.offset = 0;
506 ov_front.data.memory_id = frame_fd;
507 notify_camframe_fb_thread();
508
509 return true;
510 }
511
mm_app_dl_render(int frame_fd,struct crop_info * cropinfo)512 int mm_app_dl_render(int frame_fd, struct crop_info * cropinfo)
513 {
514 struct mdp_blit_req *e;
515 int croplen = 0;
516 //struct crop_info *cropinfo;
517 common_crop_t *crop;
518
519 //cropinfo = (struct crop_info *)vb->input;
520 if(cropinfo != NULL) {
521 crop = (common_crop_t *)cropinfo->info;
522 }
523 /* Initialize yuv structure */
524 yuv.list.count = 1;
525 e = &yuv.list.req[0];
526
527 e->src.width = input_display.user_input_display_width;
528 e->src.height = input_display.user_input_display_height;
529 e->src.format = MDP_Y_CRCB_H2V2;
530 e->src.offset = 0;
531 e->src.memory_id = frame_fd;
532
533 e->dst.width = vinfo.xres;
534 e->dst.height = vinfo.yres;
535 e->dst.format = MDP_RGB_565;
536 e->dst.offset = 0;
537 e->dst.memory_id = fb_fd;
538
539 e->transp_mask = 0xffffffff;
540 e->flags = 0;
541 e->alpha = 0xff;
542
543 if (cropinfo != NULL && (crop->in2_w != 0 || crop->in2_h != 0)) {
544 e->src_rect.x = (crop->out2_w - crop->in2_w + 1) / 2 - 1;
545 e->src_rect.y = (crop->out2_h - crop->in2_h + 1) / 2 - 1;
546 e->src_rect.w = crop->in2_w;
547 e->src_rect.h = crop->in2_h;
548
549 e->dst_rect.x = 0;
550 e->dst_rect.y = 0;
551 e->dst_rect.w = input_display.user_input_display_width;
552 e->dst_rect.h = input_display.user_input_display_height;
553 } else {
554 e->dst_rect.x = 0;
555 e->dst_rect.y = 0;
556 e->dst_rect.w = input_display.user_input_display_width;
557 e->dst_rect.h = input_display.user_input_display_height;
558
559 e->src_rect.x = 0;
560 e->src_rect.y = 0;
561 e->src_rect.w = input_display.user_input_display_width;
562 e->src_rect.h = input_display.user_input_display_height;
563 }
564
565 overlay_set_params(e);
566
567 ov_front.data.offset = 0;
568 ov_front.data.memory_id = frame_fd;
569 notify_camframe_fb_thread();
570
571 return true;
572 }
573
574
575