/*
* Copyright 2007-2015 Freescale Semiconductor, Inc. All rights reserved.
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
/*
* @file mxc_v4l2_tvin.c
*
* @brief Mxc TVIN For Linux 2 driver test application
*
*/
/*=======================================================================
INCLUDE FILES
=======================================================================*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <stdint.h>
#include <sys/types.h>
#include <stdint.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <unistd.h>
#include <asm/types.h rel='nofollow' onclick='return false;'>
#include <linux/videodev2.h>
#include <sys/mman.h>
#include <math.h>
#include <string.h>
#include <malloc.h>
#include <sys/time.h>
#include "mxcfb.h"
#include "ipu.h"
#include "g2d.h"
#define G2D_CACHEABLE 0
#define TFAIL -1
#define TPASS 0
#define NUMBER_BUFFERS 4
char v4l_capture_dev[100] = "/dev/video0";
#ifdef BUILD_FOR_ANDROID
char fb_display_dev[100] = "/dev/graphics/fb1";
char fb_display_bg_dev[100] = "/dev/graphics/fb0";
#else
char fb_display_dev[100] = "/dev/fb1";
char fb_display_bg_dev[100] = "/dev/fb0";
#endif
int fd_capture_v4l = 0;
int fd_fb_display = 0;
int fd_ipu = 0;
unsigned char * g_fb_display = NULL;
int g_input = 1;
int g_display_num_buffers = 3;
int g_capture_num_buffers = NUMBER_BUFFERS;
int g_in_width = 0;
int g_in_height = 0;
int g_in_fmt = V4L2_PIX_FMT_UYVY;
int g_display_width = 0;
int g_display_height = 0;
int g_display_top = 0;
int g_display_left = 0;
int g_display_fmt = V4L2_PIX_FMT_UYVY;
int g_display_base_phy;
int g_display_size;
int g_display_fg = 1;
int g_display_id = 1;
struct fb_var_screeninfo g_screen_info;
int g_frame_count = 0x7FFFFFFF;
int g_frame_size;
bool g_g2d_render = 0;
int g_g2d_fmt;
int g_mem_type = V4L2_MEMORY_MMAP;
FILE *fd_capture;
struct testbuffer
{
unsigned char *start;
size_t offset;
unsigned int length;
};
struct testbuffer display_buffers[3];
struct testbuffer capture_buffers[NUMBER_BUFFERS];
struct g2d_buf *g2d_buffers[NUMBER_BUFFERS];
static void draw_image_to_framebuffer(struct g2d_buf *buf, int img_width, int img_height, int img_format,
struct fb_var_screeninfo *screen_info, int left, int top, int to_width, int to_height, int set_alpha, int rotation)
{
struct g2d_surface src, dst;
void *g2dHandle;
if (((left+to_width) > (int)screen_info->xres) || ((top+to_height) > (int)screen_info->yres)) {
printf("Bad display image dimensions!\n");
return;
}
#if G2D_CACHEABLE
g2d_cache_op(buf, G2D_CACHE_FLUSH);
#endif
if (g2d_open(&g2dHandle) == -1 || g2dHandle == NULL) {
printf("Fail to open g2d device!\n");
g2d_free(buf);
return;
}
/*
NOTE: in this example, all the test image data meet with the alignment requirement.
Thus, in your code, you need to pay attention on that.
Pixel buffer address alignment requirement,
RGB/BGR: pixel data in planes [0] with 16bytes alignment,
NV12/NV16: Y in planes [0], UV in planes [1], with 64bytes alignment,
I420: Y in planes [0], U in planes [1], V in planes [2], with 64 bytes alignment,
YV12: Y in planes [0], V in planes [1], U in planes [2], with 64 bytes alignment,
NV21/NV61: Y in planes [0], VU in planes [1], with 64bytes alignment,
YUYV/YVYU/UYVY/VYUY: in planes[0], buffer address is with 16bytes alignment.
*/
src.format = img_format;
switch (src.format) {
case G2D_RGB565:
case G2D_RGBA8888:
case G2D_RGBX8888:
case G2D_BGRA8888:
case G2D_BGRX8888:
case G2D_BGR565:
case G2D_YUYV:
case G2D_UYVY:
src.planes[0] = buf->buf_paddr;
break;
case G2D_NV12:
src.planes[0] = buf->buf_paddr;
src.planes[1] = buf->buf_paddr + img_width * img_height;
break;
case G2D_I420:
src.planes[0] = buf->buf_paddr;
src.planes[1] = buf->buf_paddr + img_width * img_height;
src.planes[2] = src.planes[1] + img_width * img_height / 4;
break;
case G2D_YV12:
src.planes[0] = buf->buf_paddr;
src.planes[2] = buf->buf_paddr + img_width * img_height;
src.planes[1] = src.planes[2] + img_width * img_height / 4;
break;
case G2D_NV16:
src.planes[0] = buf->buf_paddr;
src.planes[1] = buf->buf_paddr + img_width * img_height;
break;
default:
printf("Unsupport image format in the example code\n");
return;
}
src.left = 0;
src.top = 0;
src.right = img_width;
src.bottom = img_height;
src.stride = img_width;
src.width = img_width;
src.height = img_height;
src.rot = G2D_ROTATION_0;
dst.planes[0] = g_display_base_phy;
dst.left = left;
dst.top = top;
dst.right = left + to_width;
dst.bottom = top + to_height;
dst.stride = screen_info->xres;
dst.width = screen_info->xres;
dst.height = screen_info->yres;
dst.rot = rotation;
dst.format = screen_info->bits_per_pixel == 16 ? G2D_RGB565 : (screen_info->red.offset == 0 ? G2D_RGBA8888 : G2D_BGRA8888);
if (set_alpha) {
src.blendfunc = G2D_ONE;
dst.blendfunc = G2D_ONE_MINUS_SRC_ALPHA;
src.global_alpha = 0x80;
dst.global_alpha = 0xff;
g2d_enable(g2dHandle, G2D_BLEND);
g2d_enable(g2dHandle, G2D_GLOBAL_ALPHA);
}
g2d_blit(g2dHandle, &src, &dst);
g2d_finish(g2dHandle);
if (set_alpha) {
g2d_disable(g2dHandle, G2D_GLOBAL_ALPHA);
g2d_disable(g2dHandle, G2D_BLEND);
}
g2d_close(g2dHandle);
}
int start_capturing(void)
{
int i;
struct v4l2_buffer buf;
enum v4l2_buf_type type;
for (i = 0; i < g_capture_num_buffers; i++) {
memset(&buf, 0, sizeof (buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = g_mem_type;
buf.index = i;
if (g_mem_type == V4L2_MEMORY_USERPTR) {
buf.length = capture_buffers[i].length;
buf.m.userptr = (unsigned long)capture_buffers[i].offset;
}
if (ioctl(fd_capture_v4l, VIDIOC_QUERYBUF, &buf) < 0) {
printf("VIDIOC_QUERYBUF error\n");
return TFAIL;
}
if (g_mem_type == V4L2_MEMORY_MMAP) {
capture_buffers[i].length = buf.length;
capture_buffers[i].offset = (size_t) buf.m.offset;
capture_buffers[i].start = mmap(NULL, capture_buffers[i].length,
PROT_READ | PROT_WRITE, MAP_SHARED,
fd_capture_v4l, capture_buffers[i].offset);
memset(capture_buffers[i].start, 0xFF, capture_buffers[i].length);
}
}
for (i = 0; i < g_capture_num_buffers; i++) {
memset(&buf, 0, sizeof (buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = g_mem_type;
buf.index = i;
if (g_mem_type == V4L2_MEMORY_USERPTR)
buf.m.offset = (unsigned int)capture_buffers[i].start;
else
buf.m.offset = capture_buffers[i].offset;
buf.length = capture_buffers[i].length;
if (ioctl(fd_capture_v4l, VIDIOC_QBUF, &buf) < 0) {
printf("VIDIOC_QBUF error\n");
return TFAIL;
}
}
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (ioctl (fd_capture_v4l, VIDIOC_STREAMON, &type) < 0) {
printf("VIDIOC_STREAMON error\n");
return TFAIL;
}
return TPASS;
}
int prepare_g2d_buffers(void)
{
int i;
for (i = 0; i < g_capture_num_buffers; i++) {
#if G2D_CACHEABLE
g2d_buffers[i] = g2d_alloc(g_frame_size, 1);//alloc physical contiguous m