嵌入式软件工程师&&太极拳
全部博文(548)
分类: 嵌入式
2011-12-03 20:37:54
UVC驱动测试程序开发
视频设备数据读取操作流程:
*1. 打开设备文件。 int fd=open(”/dev/video0″,O_RDWR);
2. 取得设备的capability,看看设备具有什么功能,比如是否具有视频输入,或者音频输入输出等。VIDIOC_QUERYCAP,struct v4l2_capability
3. 选择视频输入,一个视频设备可以有多个视频输入。VIDIOC_S_INPUT,struct v4l2_input
*4. 设置视频的制式和帧格式,制式包括PAL,NTSC,帧的格式个包括宽度和高度等。
VIDIOC_S_STD,VIDIOC_S_FMT,struct v4l2_std_id,struct v4l2_format
*5. 向驱动申请帧缓冲,一般不超过5个。struct v4l2_requestbuffers
*6. 将申请到的帧缓冲映射到用户空间,这样就可以直接操作采集到的帧了,而不必去复制。mmap
*7. 将申请到的帧缓冲全部入队列,以便存放采集到的数据.VIDIOC_QBUF,struct v4l2_buffer
8. 开始视频的采集。VIDIOC_STREAMON
*9. 出队列以取得已采集数据的帧缓冲,取得原始采集数据。VIDIOC_DQBUF
*10. 将缓冲重新入队列尾,这样可以循环采集。VIDIOC_QBUF
11. 停止视频的采集。VIDIOC_STREAMOFF
*12. 关闭视频设备。close(fd);
加*的为,最基本过程。
该测试程序为最简单的测试程序,他只测试驱动必须实现的对应的V4L2的最基本接口。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
uvcvideo<-videodev,v4l1_compat
UVCVIDEO即UVC驱动(免驱驱动)它依赖VIDEODEV,V4L1_COMPAT(V4L2向前兼容模块)
int start_capturing(int fd_v4l)
{
unsigned int i=0;
struct v4l2_buffer buf;
enum v4l2_buf_type type;
memset(&buf, 0, sizeof (buf));//向驱动申请缓冲buf
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (ioctl(fd_v4l, VIDIOC_QUERYBUF, &buf) < 0)//是否申请成功
{
printf(“VIDIOC_QUERYBUF error\n”);
return -1;
}
buffers.length = buf.length;
buffers.offset = (size_t) buf.m.offset;
buffers.start = mmap (NULL, buffers.length,PROT_READ | PROT_WRITE, MAP_SHARED, fd_v4l, buffers.offset);
//以内存映射方式将申请的驱动缓冲映射到用户空间buffers中
if (ioctl (fd_v4l, VIDIOC_QBUF, &buf) < 0)
{
printf(“VIDIOC_QBUF error\n”);
return -1;
}//驱动缓冲区是否可以输出
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//设置缓冲区buf类型
int v4l_capture_setup(void)//抓图前准备工作
{ char * v4l_device = “/dev/video0″;
struct v4l2_format fmt;
struct v4l2_control ctrl;
int fd_v4l = 0;
struct v4l2_crop crop;
if ((fd_v4l = open(v4l_device, O_RDWR, 0)) < 0)
{
printf(“Unable to open %s\n”, v4l_device);
return 0;
}
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
//fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
//fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
//fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB565;
fmt.fmt.pix.width = g_width;
fmt.fmt.pix.height = g_height;
//printf (“fmt.fmt.pix.sizeimage =%d\n”,fmt.fmt.pix.sizeimage);
if (ioctl(fd_v4l, VIDIOC_S_FMT, &fmt) < 0)//设置视频格式
{
//printf(“set format failed\n”);
printf(“not a mjpeg format \n”);
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
}
if (ioctl(fd_v4l, VIDIOC_S_FMT, &fmt) < 0)
{
//printf(“set format failed\n”);
printf(“not a jpeg format \n”);
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB565;
}
if (ioctl(fd_v4l, VIDIOC_S_FMT, &fmt) < 0)
{
//printf(“set format failed\n”);
printf(“not a mjpeg format \n”);
printf(“set format failed\n”);
return 0;
}
//printf (“fmt.fmt.pix.sizeimage =%d\n”,fmt.fmt.pix.sizeimage);
ctrl.id = V4L2_CID_BRIGHTNESS ;
//ctrl.value = V4L2_CTRL_TYPE_INTEGER + 0;
ctrl.value = g_rotate;
if (ioctl(fd_v4l, VIDIOC_S_CTRL, &ctrl) < 0)//设置控制信息
{
printf(“set ctrl failed\n”);
return 0;
}
int v4l_capture_test(int fd_v4l, const char * file)//抓图过程
{
int i;
struct v4l2_buffer buf;
struct v4l2_buffer temp_buf;
struct v4l2_format fmt;
FILE * fd_y_file = 0;
int count = g_capture_count;//=1
if ((fd_y_file = fopen(file, “wb”)) < 0)//打开设备
{
printf(“Unable to create y frame recording file\n”);
return -1;
}
//printf (“fopen_return_fd_y_file = %d \n”,fd_y_file);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//设置视频格式类型,必须与v4l2_buf_type一致
if (ioctl(fd_v4l, VIDIOC_G_FMT, &fmt) < 0)//获得驱动支持格式,V4L2_format 确定
{
printf(“get format failed\n”);
return -1;
}
else
{
printf(“Width = %d\n”, fmt.fmt.pix.width);//输出v4l2_format 的信息
printf(“Height = %d\n”, fmt.fmt.pix.height);
//printf(“Image size = %d\n”, imagesize);
printf(“Image size = %d\n”, fmt.fmt.pix.sizeimage);
printf(“pixelformat = %d\n”, fmt.fmt.pix.pixelformat);
}
if (start_capturing(fd_v4l) < 0)//最开始是否可以抓图
{
printf(“start_capturing failed\n”);
return -1;
}
memset(&buf, 0, sizeof (buf));//初始化缓冲区空间
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//设置输出视频类型,必须与v4l2_buf_type一致
buf.memory = V4L2_MEMORY_MMAP;//采用内存映射方式,将数据映射到用户空间
if (ioctl (fd_v4l, VIDIOC_DQBUF, &buf) < 0)printf(“VIDIOC_DQBUF failed.\n”);//缓冲区数据申请出队
//printf (“fwrite start \n”);
//printf (“size = %d \n”,fmt.fmt.pix.sizeimage);
unsigned char *ptcur = buffers.start;
// printf (“buf.bytesused = %d \n”,buf.bytesused);
int i1;
for(i1=0; i1
if((buffers.start[i1] == 0×000000FF) && (buffers.start[i1+1] == 0×000000C4)) {
printf(“huffman table finded! \nbuf.bytesused = %d\nFFC4 = %d \n”,buf.bytesused,i1);
break;
}
}
if(i1 == buf.bytesused)//若无哈弗曼表,则将数据全部输出
{
printf(“huffman table don’t exist! \n”);
printf (“buf.bytesused = %d \n”,buf.bytesused);
if(buf.bytesused == 0)return -1;
fwrite(buffers.start, buf.bytesused, 1, fd_y_file);
printf (“fwrite all end \n”);
}
else //若有哈弗曼表,则从jpeg图像开始处FFD8,写入文件
{
for(i=0; i
if((buffers.start[i] == 0×000000FF) && (buffers.start[i+1] == 0×000000D8)) break;
ptcur++;
}
printf(“i = %d,FF = %02x,D8 = %02x\n”,i,buffers.start[i],buffers.start[i+1]);
int imagesize =buf.bytesused – i;
// int imagesize = fmt.fmt.pix.sizeimage;
// printf (“buf.bytesused = %d \n”,buf.bytesused);
printf (“imagesize = %d \n”,imagesize);
if(imagesize == 0)return -1;
fwrite(ptcur, imagesize, 1, fd_y_file);
printf (“fwrite end \n”);
}
fclose(fd_y_file);
close(fd_v4l);
return 0;
}
用arm-linux-gcc-4.3.2编译成功,下载至mini2440,./capture file.jpg,通过文件查看,可以看见图像。