uvc摄像头就是最常用的u***免驱摄像头,Linux内核都支持,但是有的内核并没有把uvc编译进内核而是以module的形式提供,需要使用modprobe uvcvideo安装驱动,或者配置内核吧uvc配置成编译进内核重新烧写系统。
使用uvc摄像头和使用其他设备一样都是打开设备文件然后使用ioctl进行摄像头的参数获取和配置,配置代码如下:
- int VideoInit(struct VideoDev *video)
- {
- unsigned int i;
- int ret;
- //帧的格式,比如宽度,高度等
- CLEAR (video->format);
- video->format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //数据流类型,必须永远是V4L2_BUF_TYPE_VIDEO_CAPTURE
- video->format.fmt.pix.width = 640;//宽,必须是16的倍数
- video->format.fmt.pix.height = 480;//高,必须是16的倍数
- video->format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;//视频数据存储类型//V4L2_PIX_FMT_YUYV;//V4L2_PIX_FMT_YVU420;//V4L2_PIX_FMT_YUYV;
- video->format.fmt.pix.field = V4L2_FIELD_INTERLACED;
- //设置当前驱动的频捕获格式
- ret = ioctl (video->fd, VIDIOC_S_FMT, &video->format);
- if(ret < 0)
- {
- printf("failture VIDIOC_S_FMTn");
- return -1;
- }
- /*4.向驱动申请帧缓冲,一般不超过5个。struct v4l2_requestbuffers*/
- struct v4l2_requestbuffers req;
- CLEAR (req);
- req.count = 4;//缓存数量,也就是说在缓存队列里保持多少张照片
- req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- req.memory = V4L2_MEMORY_MMAP;//或V4L2_MEMORY_USERPTR
- ret = ioctl (video->fd, VIDIOC_REQBUFS, &req); //申请缓冲,count是申请的数量
- if(ret < 0)
- printf("failture VIDIOC_REQBUFSn");
- if (req.count < 1)
- printf("Insufficient buffer memoryn");
-
- video->buffers = (struct buffer *)calloc (req.count, sizeof (struct buffer)); //内存中建立对应空间
- /*5.将申请到的帧缓冲映射到用户空间,这样就可以直接操作采集到的帧了,而不必去复制。mmap*/
- for (video->n_buffers = 0; video->n_buffers < req.count; ++video->n_buffers)
- {
- struct v4l2_buffer buf; //驱动中的一帧
- CLEAR (buf);
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory = V4L2_MEMORY_MMAP;
- buf.index = video->n_buffers;
- //把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址
- if (-1 == ioctl (video->fd, VIDIOC_QUERYBUF, &buf)) //映射用户空间
- printf ("VIDIOC_QUERYBUF errorn");
- video->buffers[video->n_buffers].length = buf.length;
- video->buffers[video->n_buffers].start = mmap (NULL /* start anywhere */, buf.length, PROT_READ | PROT_WRITE /* required */, MAP_SHARED /* recommended */, video->fd, buf.m.offset); //通过mmap建立映射关系,返回映射区的起始地址
- if (MAP_FAILED == video->buffers[video->n_buffers].start)
- printf ("mmap failedn");
- }
- /*6.将申请到的帧缓冲全部入队列,以便存放采集到的数据.VIDIOC_QBUF,struct v4l2_buffer*/
- for (i = 0; i < video->n_buffers; ++i)
- {
- struct v4l2_buffer buf;
- CLEAR (buf);
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory = V4L2_MEMORY_MMAP;
- buf.index = i;
- //把数据从缓存中读取出来
- if (-1 == ioctl (video->fd, VIDIOC_QBUF, &buf))//申请到的缓冲进入列队
- printf ("VIDIOC_QBUF failedn");
- }
- }
复制代码
获取一帧图像可以根据摄像头支持的图片格式获取,我这里的摄像头比较low,只支持30万像素的yuyv格式,采集图像代码如下:
- int VideoGetFrame(struct VideoDev *video,unsigned char *image_buf)
- {
- struct v4l2_buffer buf;
- unsigned int i;
- int ret;
- CLEAR (buf);
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory = V4L2_MEMORY_MMAP;
- ret = ioctl (video->fd, VIDIOC_DQBUF, &buf);
- if(ret < 0)
- printf("failture VIDIOC_DQBUFn"); //出列采集的帧缓冲
-
- // printf ("buf.index dq is %d,n", buf.index);
-
- /*9.将缓冲重新入队列尾,这样可以循环采集。VIDIOC_QBUF*/
- ret = ioctl (video->fd, VIDIOC_QBUF, &buf); //再将其入列
- if(ret < 0) //把数据从缓存中读取出来
- printf("failture VIDIOC_QBUFn");
- // fwrite(video->buffers[buf.index].start, video->buffers[buf.index].length, 1, file_fd); //将其写入文件中
-
- if(image_buf != NULL) //如果image_buf不为空的话则进行数据拷贝
- memcpy(image_buf,video->buffers[buf.index].start,video->buffers[buf.index].length);
- return video->buffers[buf.index].length;
- }
复制代码
得到的yuyv图片数据就可以在Windows上使用yuyv查看软件进行查看了。下一篇文章准备使用libjpeg库对yuyv图片进行编码转换成jpeg图片。
|