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