V4L2框架
0 查看videodev2
0.1 头文件/usr/include/linux/videodev2.h
0.2 使用ioctl函数
使用ioctl函数
// 添加头文件
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>int ioctl (int __fd, unsigned long int __request, ...)
- 查看对于结构
/usr/include/linux/videodev2.h
1打开设备
1.1 查看设备
ls /dev/v*
1.2 打开摄像头
cheese
video_step1.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{//1.打开设备int fd = open("/dev/video0", O_RDWR);if(fd < 0){perror("打开设备失败");return -1;}printf("打开设备成功");//9.关闭设备close(fd);return 0;
}
2.配置支持格式
获取摄像头格式的命令 :VIDEOC_ENUM_FMT,
对应存储格式的结构体 :v4l2_fmtdesc
#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>
int main(void)
{//1.打开设备int fd = open("/dev/video0", O_RDWR);if(fd < 0){perror("打开设备失败");return -1;}//2.获取摄像头支持的格式ioctl(文件描述符, 命令, 与命令对应的结构体)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]);printf("--------------------------------------------\n");}//9.关闭设备close(fd);return 0;
}
可以才看到配置
3、配置摄像头采集格式
配置摄像头采集格式的命令 :VIDIOC_S_FMT ,
对应存储格式的结构体 :v4l2_format
- 结构体v4l2_format格式
#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 <string.h>int main(void)
{//1.打开设备int fd = open("/dev/video0", O_RDWR);if(fd < 0){perror("打开设备失败");return -1;}//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;int ret = ioctl(fd, VIDIOC_S_FMT, &vfmt);if(ret < 0){perror("设置格式失败");}//结构体清空memset(&vfmt, 0, sizeof(vfmt));//获取配置vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;ret = ioctl(fd, VIDIOC_G_FMT, &vfmt);if(ret < 0){perror("获取格式失败");}if(vfmt.fmt.pix.width == 640 && vfmt.fmt.pix.height == 480 && vfmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV){printf("设置成功\n");}else{printf("设置失败\n");}//9.关闭设备close(fd);return 0;
}
4.申请内核缓冲区队列
申请内核缓冲区队列的命令 : VIDIOC_REQBUFS ,
对应存储格式的结构体 : v4l2_requestbuffers
#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 <string.h>int main(void)
{//1.打开设备int fd = open("/dev/video0", O_RDWR);if(fd < 0){perror("打开设备失败");return -1;}//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;//设置视频采集格式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("申请队列空间失败");}else{printf("申请队列空间成功");}//9.关闭设备close(fd);return 0;
}
5.把内核的缓冲区队列映射到用户空间
队列映射到用户空间的命令 : VIDIOC_QUERYBUF , VIDIOC_QBUF
对应存储格式的结构体 : v4l2_buffer
#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 <string.h>
#include <sys/mman.h>int main(void)
{//1.打开设备int fd = open("/dev/video0", O_RDWR);if(fd < 0){perror("打开设备失败");return -1;}//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;//设置视频采集格式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, indexmapbuffer.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("放回失败");}}//9.关闭设备close(fd);return 0;
}
6 开始采集,停止采集,释放映射
采集的命令 :
- VIDIOC_STREAMON(开始采集写数据到队列中)
- VIDIOC_DQBUF(告诉内核我要某一个数据,内核不可以修改)
- VIDIOC_QBUF(告诉内核我已经使用完毕)
- VIDIOC_STREAMOFF(停止采集-不在向队列中写数据)
#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 <string.h>
#include <sys/mman.h>int main(void)
{//1.打开设备int fd = open("/dev/video0", O_RDWR);if(fd < 0){perror("打开设备失败");return -1;}//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_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, indexmapbuffer.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("开启失败");}//从队列中提取一帧数据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.jpg", "w+");//mptr[readbuffer.index]fwrite(mptr[readbuffer.index], readbuffer.length, 1, file);fclose(file);//通知内核已经使用完毕ret = ioctl(fd, VIDIOC_QBUF, &readbuffer);if(ret < 0){perror("放回队列失败");}//停止采集ret = ioctl(fd, VIDIOC_STREAMOFF, &type);//释放映射for(int i=0; i<4; i)munmap(mptr[i], size[i]);//9.关闭设备close(fd);return 0;
}
V4L2框架
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FqvRWjxh-1666608345812)(D:\Slam\文档\V4L2框架.assets\image-20221022154652055.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5JKfpjoW-1666608345814)(D:\Slam\文档\V4L2框架.assets\image-20221023222816576.png)]
0 查看videodev2
0.1 头文件/usr/include/linux/videodev2.h
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DL45KmnX-1666608345816)(D:\Slam\文档\V4L2框架.assets\image-20221024003546390.png)]
0.2 使用ioctl函数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w3WdXvBY-1666608345817)(https://note.youdao.com/yws/public/resource/7c4c0e28888d03ec70d339118c374edb/xmlnote/8D211CB4C14A49C9AD1E4F4214996D25/44230)]
使用ioctl函数
// 添加头文件
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>int ioctl (int __fd, unsigned long int __request, ...)
- 查看对于结构
/usr/include/linux/videodev2.h
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QSVYnUY3-1666608345818)(D:\Slam\文档\V4L2框架.assets\image-20221023225848269.png)]
1打开设备
1.1 查看设备
ls /dev/v*
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dg8qfENM-1666608345820)(D:\Slam\文档\V4L2框架.assets\image-20221024002629205.png)]
1.2 打开摄像头
cheese
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V8ndV3hD-1666608345821)(D:\Slam\文档\V4L2框架.assets\image-20221024002758756.png)]
video_step1.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{//1.打开设备int fd = open("/dev/video0", O_RDWR);if(fd < 0){perror("打开设备失败");return -1;}printf("打开设备成功");//9.关闭设备close(fd);return 0;
}
2.配置支持格式
获取摄像头格式的命令 :VIDEOC_ENUM_FMT,
对应存储格式的结构体 :v4l2_fmtdesc
#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>
int main(void)
{//1.打开设备int fd = open("/dev/video0", O_RDWR);if(fd < 0){perror("打开设备失败");return -1;}//2.获取摄像头支持的格式ioctl(文件描述符, 命令, 与命令对应的结构体)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]);printf("--------------------------------------------\n");}//9.关闭设备close(fd);return 0;
}
可以才看到配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AoPEWQ7F-1666608345822)(D:\Slam\文档\V4L2框架.assets\image-20221024002117533.png)]
3、配置摄像头采集格式
配置摄像头采集格式的命令 :VIDIOC_S_FMT ,
对应存储格式的结构体 :v4l2_format
- 结构体v4l2_format格式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oqoCmlMw-1666608345824)(D:\Slam\文档\V4L2框架.assets\image-20221024003236175.png)]
#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 <string.h>int main(void)
{//1.打开设备int fd = open("/dev/video0", O_RDWR);if(fd < 0){perror("打开设备失败");return -1;}//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;int ret = ioctl(fd, VIDIOC_S_FMT, &vfmt);if(ret < 0){perror("设置格式失败");}//结构体清空memset(&vfmt, 0, sizeof(vfmt));//获取配置vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;ret = ioctl(fd, VIDIOC_G_FMT, &vfmt);if(ret < 0){perror("获取格式失败");}if(vfmt.fmt.pix.width == 640 && vfmt.fmt.pix.height == 480 && vfmt.fmt.pix.pixelformat == V4L2_PIX_FMT_YUYV){printf("设置成功\n");}else{printf("设置失败\n");}//9.关闭设备close(fd);return 0;
}
4.申请内核缓冲区队列
申请内核缓冲区队列的命令 : VIDIOC_REQBUFS ,
对应存储格式的结构体 : v4l2_requestbuffers
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BGS10VfN-1666608345825)(D:\Slam\文档\V4L2框架.assets\image-20221024163914484.png)]
#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 <string.h>int main(void)
{//1.打开设备int fd = open("/dev/video0", O_RDWR);if(fd < 0){perror("打开设备失败");return -1;}//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;//设置视频采集格式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("申请队列空间失败");}else{printf("申请队列空间成功");}//9.关闭设备close(fd);return 0;
}
5.把内核的缓冲区队列映射到用户空间
队列映射到用户空间的命令 : VIDIOC_QUERYBUF , VIDIOC_QBUF
对应存储格式的结构体 : v4l2_buffer
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mz8xX0C1-1666608345827)(D:\Slam\文档\V4L2框架.assets\image-20221024163857963.png)]
#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 <string.h>
#include <sys/mman.h>int main(void)
{//1.打开设备int fd = open("/dev/video0", O_RDWR);if(fd < 0){perror("打开设备失败");return -1;}//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;//设置视频采集格式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, indexmapbuffer.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("放回失败");}}//9.关闭设备close(fd);return 0;
}
6 开始采集,停止采集,释放映射
采集的命令 :
- VIDIOC_STREAMON(开始采集写数据到队列中)
- VIDIOC_DQBUF(告诉内核我要某一个数据,内核不可以修改)
- VIDIOC_QBUF(告诉内核我已经使用完毕)
- VIDIOC_STREAMOFF(停止采集-不在向队列中写数据)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uxfBpLo6-1666608345829)(D:\Slam\文档\V4L2框架.assets\image-20221024153801352.png)]
#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 <string.h>
#include <sys/mman.h>int main(void)
{//1.打开设备int fd = open("/dev/video0", O_RDWR);if(fd < 0){perror("打开设备失败");return -1;}//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_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, indexmapbuffer.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("开启失败");}//从队列中提取一帧数据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.jpg", "w+");//mptr[readbuffer.index]fwrite(mptr[readbuffer.index], readbuffer.length, 1, file);fclose(file);//通知内核已经使用完毕ret = ioctl(fd, VIDIOC_QBUF, &readbuffer);if(ret < 0){perror("放回队列失败");}//停止采集ret = ioctl(fd, VIDIOC_STREAMOFF, &type);//释放映射for(int i=0; i<4; i)munmap(mptr[i], size[i]);//9.关闭设备close(fd);return 0;
}