V4L2编程以及LCD显示
头文件;
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/ioctl.h>
#include<linux/videodev2.h>
#include<sys/mman.h>
//#include<jpeglib.h>
#include<string.h>
#include<linux/fb.h>
查看摄像头支持照片的格式
//2获取摄像头支持的格式ioctl(文件描述符,命令,与命令对应的结构体)
//struct v412_fmtdesc v4fmt;
/* struct v4l2_fmtdesc v4fmt;
v4fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
int i=0;
while(1){
v4fmt.index = i++;
int ret = ioctl(fd,VIDIOC_ENUM_FMT,&v4fmt);
if(ret<0)
{
perror("获取失败");
break;
}
printf("index=%d\n",v4fmt.index);
printf("flags=%d\n",v4fmt.flags);
printf("description=%s\n",v4fmt.description);
unsigned char *p =(unsigned char *)&v4fmt.pixelformat;
printf("pixelformat=%c%c%c%c\n",p[0],p[1],p[2],p[3]);
printf("reserved=%d\n",v4fmt.reserved[0]);
}*/
YUYV格式转化
void yuyv_to_rgb(unsigned char *yuyvdata,unsigned char *rgbdata,int w,int h)
{
int r1,g1,b1;
int r2,g2,b2;
for(int i=0;i<w*h/2;i++)
{
char data[4];
memcpy(data,yuyvdata+i*4,4);
unsigned char Y0=data[0];
unsigned char U0=data[1];
unsigned char Y1=data[2];
unsigned char V1=data[3];
r1 = Y0+1.4075*(V1-128);if(r1>255)r1=255;if(r1<0)r1=0;
g1 = Y0-0.3455*(U0-128)-0.7169*(V1-128);if(g1>255)g1=255;if(g1<0)g1=0;
b1 = Y0+1.779*(U0-128);if(b1>255)b1=255;if(b1<0)b1=0;
r2 = Y1+1.4075*(V1-128);if(r2>255)r2=255;if(r2<0)r2=0;
g2 = Y1-0.3455*(U0-128)-0.7169*(V1-128);if(g2>255)g2=255;if(g2<0)g2=0;
b2 = Y1+1.779*(U0-128);if(b2>255)b2=255;if(b2<0)b2=0;
rgbdata[i*6+0]=r1;
rgbdata[i*6+1]=g1;
rgbdata[i*6+2]=b1;
rgbdata[i*6+3]=r2;
rgbdata[i*6+4]=g2;
rgbdata[i*6+5]=b2;
}
调取本地LCD进行显示
int lcdfd =0;
unsigned int *lcdptr =NULL;
int lcd_w=800,lcd_h=480;
void lcd_show_rgb(unsigned char *rgbdata,int w,int h)
{
unsigned int *ptr =lcdptr;
for(int i =0;i<h;i++)
{
for(int j=0;j<w;j++)
{
memcpy(ptr+j,rgbdata+j*3,3);
}
ptr+=lcd_w;
rgbdata+=w*3;
}
}
V4l2编程具体流程
//1打开设备
int fd =open("/dev/video0",O_RDWR);
if(fd<0)
{
perror("打开设备失败");
return -1;
}
//2获取摄像头支持的格式ioctl(文件描述符,命令,与命令对应的结构体)
//struct v412_fmtdesc v4fmt;
/* struct v4l2_fmtdesc v4fmt;
v4fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
int i=0;
while(1){
v4fmt.index = i++;
int ret = ioctl(fd,VIDIOC_ENUM_FMT,&v4fmt);
if(ret<0)
{
perror("获取失败");
break;
}
printf("index=%d\n",v4fmt.index);
printf("flags=%d\n",v4fmt.flags);
printf("description=%s\n",v4fmt.description);
unsigned char *p =(unsigned char *)&v4fmt.pixelformat;
printf("pixelformat=%c%c%c%c\n",p[0],p[1],p[2],p[3]);
printf("reserved=%d\n",v4fmt.reserved[0]);
}*/
//3设置采集格式
struct v4l2_format vfmt;
vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//摄像头采集
vfmt.fmt.pix.width = 640;//设置宽
vfmt.fmt.pix.height = 480;//设置高
vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;//设置视频采集格式
// vfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
int ret = ioctl(fd,VIDIOC_S_FMT,&vfmt);
if(ret<0)
{
perror("设置格式失败");
}
//4申请内核空间
struct v4l2_requestbuffers reqbuffer;
reqbuffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuffer.count =4;//申请4个缓存区
reqbuffer.memory = V4L2_MEMORY_MMAP;//映射方式
ret = ioctl(fd,VIDIOC_REQBUFS,&reqbuffer);
if(ret<0)
{
perror("申请队列空间失败");
}
//5映射
unsigned char *mptr[4];//保存映射后用户空间的首地址
unsigned int size[4];
struct v4l2_buffer mapbuffer;
//初始化type ,index
mapbuffer.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;//摄像头采集
for(int i=0;i<4;i++)
{
mapbuffer.index =i;
ret = ioctl(fd,VIDIOC_QUERYBUF,&mapbuffer);//从内核空间查询一个空间做映设
if(ret<0)
{
perror("查询内核空间队列失败");
}
mptr[i] =(unsigned char*) mmap(NULL,mapbuffer.length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,mapbuffer.m.offset);
size[i] =mapbuffer.length;
//通知使用完毕,放回去
ret= ioctl(fd,VIDIOC_QBUF,&mapbuffer);
if(ret<0)
{
perror("放回失败");
}
}
//6开始采集
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret =ioctl(fd,VIDIOC_STREAMON,&type);
if(ret<0)
{
perror("开启失败");
}
//定义一个空间存储解码后的RGB数据
unsigned char rgbdata[640*480*3];
while(1)
{
// 从队列中提取一帧数
struct v4l2_buffer readbuffer;
readbuffer.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(fd,VIDIOC_DQBUF,&readbuffer);
if(ret<0)
{
perror("提取失败");
}
// FILE *file = fopen("my.jpeg","w");
// mptr[readbuffer,index]
// fwrite(mptr[readbuffer.index],readbuffer.length,1,file);
// close(file);
//显示到lcd上
{
yuyv_to_rgb(mptr[readbuffer.index],rgbdata,640,480);//吧JPEG数据解码为rgb数据
lcd_show_rgb(rgbdata,640,480);
}
//通知内核已经使用完毕
ret= ioctl(fd,VIDIOC_QBUF,&readbuffer);
if(ret<0)
{
perror("放回队列失败");
}
}
//7停止采集
ret = ioctl(fd,VIDIOC_STREAMOFF,&type);
//8释放映设
for(int i=0;i<4;i++)
{
munmap(mptr[i],size[i]);
}
//9关闭设备
close(fd);
return 0;