[国嵌攻略][171][V4L2图像编程接口深度学习]
V4L2摄像编程模型
1.打开摄像头设备文件
2.获取驱动信息-VIDIOC_QUERYCAP
3.设置图像格式-VIDIOC_S_FMT
4.申请帧缓冲-VIDIOC_REQBUFS
5.获取帧缓冲的地址长度信息-VIDIOC_QUERYBUF
6.使用mmap把内核空间的帧缓冲映射到用户空间
7.帧缓冲入队列-VIDIOC_QBUF
8.开始采集图像-VIDIOC_STREAMON
9.取出帧缓冲(出队)-VIDIOC_DQBUF
10.访问帧缓冲
11.帧缓冲重新入队-VIDIOC_QBUF
USB摄像头驱动工作流程
摄像头驱动从输入队列中取出一个帧缓冲,放到输出队列中。
应用程序从输出队列中取出一个帧缓冲,读取数据后,再把帧缓冲放入输入缓存中。
camera.c
#include <stdio.h> #include <malloc.h> #include <fcntl.h> #include <sys/mman.h> #include <linux/videodev2.h> struct buffer{ void *start; //帧缓冲地址 int length; //帧缓冲长度 }; int main(int argc, char **argv){ //创建图片文件 int fd_img; fd_img = open("img.jpg", O_RDWR | O_CREAT, 0777); //打开设备文件 int fd_dev; fd_dev = open("/dev/video0", O_RDWR | O_NONBLOCK, 0); //获取驱动信息 struct v4l2_capability cap; ioctl(fd_dev, VIDIOC_QUERYCAP, &cap); printf("Driver name:%s\nCard name:%s\nBus info:%s\n\n", cap.driver, cap.card, cap.bus_info); //设置图像格式 struct v4l2_format fmt; fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = 320; fmt.fmt.pix.height = 240; fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; ioctl(fd_dev, VIDIOC_S_FMT, &fmt); //申请图像缓冲 struct v4l2_requestbuffers req; req.count = 4; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; ioctl(fd_dev, VIDIOC_REQBUFS, &req); //映射用户空间 int i; struct buffer *buffs; struct v4l2_buffer buff; buffs = calloc(req.count, sizeof(*buffs)); for(i = 0; i < req.count; i++){ //获取缓冲长度 buff.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buff.memory = V4L2_MEMORY_MMAP; buff.index = i; ioctl(fd_dev, VIDIOC_QUERYBUF, &buff); buffs[i].length = buff.length; //映射缓冲地址 buffs[i].start = mmap(NULL, buff.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd_dev, buff.m.offset); } //图像缓冲入队 for(i = 0; i < req.count; i++){ buff.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buff.memory = V4L2_MEMORY_MMAP; buff.index = i; ioctl(fd_dev, VIDIOC_QBUF, &buff); } //捕获图像数据 enum v4l2_buf_type type; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ioctl(fd_dev, VIDIOC_STREAMON, &type); //等待捕获完成 fd_set fds; FD_ZERO(&fds); FD_SET(fd_dev, &fds); select(fd_dev + 1, &fds, NULL, NULL, NULL); //图像缓冲出队 buff.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buff.memory = V4L2_MEMORY_MMAP; ioctl(fd_dev, VIDIOC_DQBUF, &buff); //读取图像数据 write(fd_img, buffs[buff.index].start, buffs[buff.index].length); //图像缓冲入队 ioctl(fd_dev, VIDIOC_QBUF, &buff); //释放用户空间 for(i = 0; i < req.count; i++){ munmap(buffs[i].start, buffs[i].length); } //关闭打开文件 close(fd_dev); close(fd_img); printf("Camera done!\n"); return 0; }