#include "camera.h"
//封装yuv转换成rgb的函数
int yuvtorgb(int y,int u,int v)
{
int point;
//YUYV-->两组RGB
int r,g,b; //定义了rgb三个分量
b = 1164*(y - 16)/1000 + 2018*(u - 128)/1000;
g = 1164*(y - 16)/1000 - 813*(v - 128)/1000 - 391*(u - 128)/1000;
r = 1164*(y - 16)/1000 + 1596*(v - 128)/1000;
//处理值越界的情况
if(r>255)
r=255;
if(g>255)
g=255;
if(b>255)
b=255;
if(r<0)
r=0;
if(g<0)
g=0;
if(b<0)
b=0;
//将rgb转换成ARGB返回
point=0x00<<24|r<<16|g<<8|b;
return point;
}
//封装将一整个画面yuv数据--》rgb数据的函数
int yuvbuftorgbbuf(char *yuvbuf,int *rgbbuf)// 10
{
int i,j;
for(i=0,j=0; j<640*480; i+=4,j+=2)
{
rgbbuf[j]=yuvtorgb(yuvbuf[i],yuvbuf[i+1],yuvbuf[i+3]);
rgbbuf[j+1]=yuvtorgb(yuvbuf[i+2],yuvbuf[i+1],yuvbuf[i+3]);
}
/* yuvtorgb(yuvbuf[0],yuvbuf[1],yuvbuf[3])
yuvtorgb(yuvbuf[2],yuvbuf[1],yuvbuf[3])
yuvtorgb(yuvbuf[4],yuvbuf[5],yuvbuf[7])
yuvtorgb(yuvbuf[6],yuvbuf[5],yuvbuf[7]) */
}
int camera_show(void)
{
//打开lcd
lcdfd=open("/dev/fb0",O_RDWR);
if(lcdfd==-1)
{
perror("打开液晶屏失败!\n");
return -1;
}
//映射lcd首地址
lcdmem=mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcdfd,0);
if(lcdmem==NULL)
{
perror("映射lcd失败!\n");
return -1;
}
printf("1111\n");
//1-打开摄像头的驱动
camerafd=open("/dev/video7",O_RDWR);
if(camerafd==-1)
{
perror("打开摄像头的驱动失败!\n");
return -1;
}
//2-设置摄像头的采集格式
struct v4l2_format myfmt;
bzero(&myfmt,sizeof(myfmt));
myfmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
myfmt.fmt.pix.width=640;
myfmt.fmt.pix.height=480;
myfmt.fmt.pix.pixelformat=V4L2_PIX_FMT_YUYV; //yuv格式
myfmt.fmt.pix.field =V4L2_FIELD_NONE;
printf("222\n");
ret=ioctl(camerafd,VIDIOC_S_FMT,&myfmt);
if(ret==-1)
{
perror("设置采集格式失败!\n");
return -1;
}
//3-申请缓存
struct v4l2_requestbuffers req;
bzero(&req,sizeof(req));
req.count=4; //缓冲块数量,一般1---5之间,一个缓冲块存放一帧画面
req.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory=V4L2_MEMORY_MMAP;
ret=ioctl(camerafd,VIDIOC_REQBUFS,&req);
if(ret==-1)
{
perror("申请缓存失败!\n");
return -1;
}
printf("3333\n");
//定义指针分配堆空间存放每个缓存块的信息
struct usraddr *alladdr=calloc(4,sizeof(struct usraddr));
//分配你刚才申请的缓存
for(i=0; i<4; i++)
{
struct v4l2_buffer buf;
bzero(&buf,sizeof(buf));
buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory=V4L2_MEMORY_MMAP;
buf.index=i; //你申请的缓冲块的索引,从0开始
ret=ioctl(camerafd,VIDIOC_QUERYBUF,&buf);
if(ret==-1)
{
perror("分配缓存失败!\n");
return -1;
}
//趁热打铁,马上映射分配得到的某一块缓存
alladdr[i].someaddr=mmap(NULL,buf.length,PROT_READ|PROT_WRITE,MAP_SHARED,camerafd,buf.m.offset);
if(alladdr[i].someaddr==NULL)
{
perror("映射首地址失败!\n");
return -1;
}
alladdr[i].somelength=buf.length;
printf("4444\n");
}
//将申请到的缓存入队
for(i=0; i<4; i++)
{
struct v4l2_buffer buf;
bzero(&buf,sizeof(buf));
buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory=V4L2_MEMORY_MMAP;
buf.index=i; //你申请的缓冲块的索引,从0开始
ret=ioctl(camerafd,VIDIOC_QBUF,&buf);
if(ret==-1)
{
perror("入队失败!\n");
return -1;
}
}
printf("5555\n");
//开始采集
enum v4l2_buf_type mytype;
mytype=V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret=ioctl(camerafd,VIDIOC_STREAMON,&mytype);
if(ret==-1)
{
perror("开始采集失败!\n");
return -1;
}
//定义指针存放yuv转换得到的完整rgb
int *rgbbuf=malloc(640*480*4);
//定义超时时间1秒
struct timeval mytime;
bzero(&mytime,sizeof(mytime));
mytime.tv_sec=1;
//循环入队出队显示视频流,顺便用多路复用检测是否真的开始采集有数据了
while(1) //fd1 fd2 fd3 --》FD_ISSET()
{
fd_set myset;//读就绪
FD_ZERO(&myset);
FD_SET(camerafd,&myset);
printf("6666\n");
select(camerafd+1,&myset,NULL,NULL,&mytime); //如果视频监控有数据,select就不会阻塞
//检测到有数据了,就立马出队并显示出来
for(i=0; i<4; i++)
{
struct v4l2_buffer buf;
bzero(&buf,sizeof(buf));
buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory=V4L2_MEMORY_MMAP;
buf.index=i; //你申请的缓冲块的索引,从0开始
ret=ioctl(camerafd,VIDIOC_DQBUF,&buf);
if(ret==-1)
{
perror("出队失败!\n");
return -1;
}
ret=ioctl(camerafd,VIDIOC_QBUF,&buf);
if(ret==-1)
{
perror("入队失败!\n");
return -1;
}
//将出队的画面数据显示在开发板的液晶屏上 yuv格式-->rgb格式显示
yuvbuftorgbbuf(alladdr[i].someaddr,rgbbuf);
//将转换得到的ARGB显示在开发板的液晶屏上
for(j=0; j<480; j++)
{
memcpy(lcdmem+j*800,&rgbbuf[j*640],640*4);//内存拷贝函数
}
}
}
}
int camera_stop(void)
{
enum v4l2_buf_type mytype;
mytype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(camerafd, VIDIOC_STREAMOFF, &mytype);
if(-1 == ret )
{
perror("停止监控失败!\n");
return -1;
}
}
int Get_Ts()
{
//1,打开触摸屏文件 open /dev/input/event0
int ts_fd = open("/dev/input/event0", O_RDWR);
if(-1 == ts_fd)
{
perror("open ts failed");
return -1;
}
//2,读取触摸屏文件数据 read
struct input_event xy;
int flag = 0; //标志位 :表示当前获取的坐标值的数量
while(1) //1024*600 || 800*480
{
read(ts_fd, &xy, sizeof(xy));
//printf("type:%d, code:%d, value:%d\n", xy.type, xy.code, xy.value);
if(xy.type == EV_ABS && xy.code == ABS_X && flag == 0)
{
flag = 1;
ts_x = xy.value * 800 / 1024 ; //获取x轴坐标
}
//获取y轴坐标
if(xy.type == EV_ABS && xy.code == ABS_Y && flag == 1)
{
flag = 2;
ts_y = xy.value * 480 / 600; //获取y轴坐标
}
if(flag == 2)
{
flag = 0;
printf("(%d,%d)\n", ts_x, ts_y);
break; //获取一次坐标之后结束循环
}
}
//3,关闭触摸屏文件 close
close(ts_fd);
}