1/*
2Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
3
4Redistribution and use in source and binary forms, with or without
5modification, are permitted provided that the following conditions are
6met:
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
17THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27IF 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>
37struct file;
38struct 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
52extern 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
63struct fb_var_screeninfo vinfo;
64struct fb_fix_screeninfo finfo;
65int fb_fd = 0;
66union {
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
72static pthread_t cam_frame_fb_thread_id;
73static int camframe_fb_exit;
74
75static int is_camframe_fb_thread_ready;
76USER_INPUT_DISPLAY_T input_display;
77
78unsigned use_overlay = 0;
79struct msmfb_overlay_data ov_front, ov_back, *ovp_front, *ovp_back;
80struct mdp_overlay overlay, *overlayp;
81int vid_buf_front_id, vid_buf_back_id;
82static unsigned char please_initialize = 1;
83int num_of_ready_frames = 0;
84
85static pthread_cond_t  sub_thread_ready_cond  = PTHREAD_COND_INITIALIZER;
86static pthread_mutex_t sub_thread_ready_mutex = PTHREAD_MUTEX_INITIALIZER;
87pthread_cond_t  camframe_fb_cond  = PTHREAD_COND_INITIALIZER;
88pthread_mutex_t camframe_fb_mutex = PTHREAD_MUTEX_INITIALIZER;
89static void notify_camframe_fb_thread();
90
91void use_overlay_fb_display_driver(void)
92{
93  use_overlay = 1;
94}
95
96void 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
159void 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 *==========================================================================*/
170void 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
257void 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
267void camframe_fb_thread_ready_signal(void);
268
269void *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
351int 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
372void 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
389void 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
405void 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
425void 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 *==========================================================================*/
459int 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
511int 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