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