mcf*_*nfs 5 c++ image-capture v4l2
我一直在努力编写 C++ 代码来从网络摄像头捕获图片。我成功地做到了,但我想对我所采取的过程进行一些澄清。
所以我的代码可以用6个步骤来描述,我将它们和我的问题一起写在这里: 一、步骤:初始化设备并设置图像格式。
const char* dev_name = "/dev/video0";
int width=320;
int height=240;
int fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0);
struct v4l2_format format = {0};
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
format.fmt.pix.width = width;
format.fmt.pix.height = height;
format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;//V4L2_PIX_FMT_YUYV //V4L2_PIX_FMT_RGB24
format.fmt.pix.field = V4L2_FIELD_NONE; //V4L2_FIELD_NONE
xioctl(fd, VIDIOC_S_FMT, &format);
Run Code Online (Sandbox Code Playgroud)
二. 步骤:请求缓冲区。
struct v4l2_requestbuffers req = {0};
req.count = 2;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
xioctl(fd, VIDIOC_REQBUFS, &req);
Run Code Online (Sandbox Code Playgroud)
三.步骤:查询缓冲区和映射。
struct v4l2_buffer buf;
buffer* buffers;
unsigned int i;
buffers = (buffer*) calloc(req.count, sizeof(*buffers));
for (i = 0; i < req.count; i++) {
clear_memmory(&(buf));
(buf).type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
(buf).memory = V4L2_MEMORY_MMAP;
(buf).index = i;
xioctl(fd, VIDIOC_QUERYBUF, &buf);
buffers[i].length = (buf).length;
printf("A buff has a len of: %i\n",buffers[i].length);
buffers[i].start = v4l2_mmap(NULL, (buf).length, PROT_READ | PROT_WRITE, MAP_SHARED,fd, (buf).m.offset);
if (MAP_FAILED == buffers[i].start) {
perror("Can not map the buffers.");
exit(EXIT_FAILURE);
}
}
Run Code Online (Sandbox Code Playgroud)
问题:我知道我在这里做了一些映射,但是有人可以解释为什么需要这样做以及到底映射了什么。对我来说,听起来实际的缓冲区在其他地方,然后我将它映射到我自己的缓冲区中,这样我就可以从缓冲区中读取内容。这是正确的吗?实际的缓冲区在哪里?
问题:我也可以避免映射吗?
四.步骤:开始串流。对缓冲区进行排队。
for (i = 0; i < 1; i++) {
clear_memmory(&(buf));
(buf).type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
(buf).memory = V4L2_MEMORY_MMAP;
(buf).index = i;
xioctl(fd,VIDIOC_QBUF, &(buf));
}
enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
xioctl(fd,VIDIOC_STREAMON, &type);
Run Code Online (Sandbox Code Playgroud)
V. 步骤:将缓冲区出队并保存一帧。
do {
FD_ZERO(&fds);
FD_SET(fd, &fds);
// Timeout.
tv.tv_sec = 2;
tv.tv_usec = 0;
r = select(fd + 1, &fds, NULL, NULL, &tv);
} while ((r == -1 && (errno = EINTR)));
if (r == -1) {
perror("select");
exit(EXIT_FAILURE);
}
clear_memmory(&(buf));
(buf).type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
(buf).memory = V4L2_MEMORY_MMAP;
xioctl(fd,VIDIOC_DQBUF, &(buf));
printf("Buff index: %i\n",(buf).index);
sprintf(out_name, "image%03d.ppm",pic_count);
fout = fopen(out_name, "w");
if (!fout) {
perror("Cannot open image");
exit(EXIT_FAILURE);
}
fwrite(buffers[(buf).index].start, (buf).bytesused, 1, fout);
fclose(fout);
pic_count++;
Run Code Online (Sandbox Code Playgroud)
请不要将我指向https://01.org/linuxgraphics/gfx-docs/drm/media/uapi/v4l/vidioc-qbuf.html或其他网站,因为我已经阅读了我能找到的所有内容,并且我我仍然有上述不清楚之处。我真的想要关于这些问题的详细解释。我预先感谢您提供的所有有用的答案。