linux v4l2 摄像头采集视频的方法
来源:互联网 发布:剑网三军爷脸数据 编辑:程序博客网 时间:2024/05/14 06:13
Linux上用v4l2函数接口获取视频主要是一个步骤流程,一步步做就很容易,现已我在qt下编写的一个读取摄像头视频的程序中的相关代码为例。
首先打开视频设备,比如/dev/video0,
- fd = open(dev_name.toStdString().c_str(), O_RDWR, 0);
-
- if(-1 == fd)
- {
- emit display_error(tr("open: %1").arg(QString(strerror(errno))));
- return -1;
- }
然后初始化设备- v4l2_capability cap;
- v4l2_cropcap cropcap;
- v4l2_crop crop;
- v4l2_format fmt;
-
- if(-1 == ioctl(fd, VIDIOC_QUERYCAP, &cap))
- {
- if(EINVAL == errno)
- {
- emit display_error(tr("%1 is no V4l2 device").arg(dev_name));
- }
- else
- {
- emit display_error(tr("VIDIOC_QUERYCAP: %1").arg(QString(strerror(errno))));
- }
- return -1;
- }
-
- if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
- {
- emit display_error(tr("%1 is no video capture device").arg(dev_name));
- return -1;
- }
-
- if(!(cap.capabilities & V4L2_CAP_STREAMING))
- {
- emit display_error(tr("%1 does not support streaming i/o").arg(dev_name));
- return -1;
- }
-
- CLEAR(cropcap);
-
- cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- if(0 == ioctl(fd, VIDIOC_CROPCAP, &cropcap))
- {
- CLEAR(crop);
- crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- crop.c = cropcap.defrect;
-
- if(-1 == ioctl(fd, VIDIOC_S_CROP, &crop))
- {
- if(EINVAL == errno)
- {
- emit display_error(tr("VIDIOC_S_CROP not supported"));
- }
- else
- {
- emit display_error(tr("VIDIOC_S_CROP: %1").arg(QString(strerror(errno))));
- return -1;
- }
- }
- }
- else
- {
- emit display_error(tr("VIDIOC_CROPCAP: %1").arg(QString(strerror(errno))));
- return -1;
- }
-
- CLEAR(fmt);
-
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt.fmt.pix.width = 640;
- fmt.fmt.pix.height = 480;
- fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
- fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
-
- if(-1 == ioctl(fd, VIDIOC_S_FMT, &fmt))
- {
- emit display_error(tr("VIDIOC_S_FMT").arg(QString(strerror(errno))));
- return -1;
- }
-
- if(-1 == init_mmap())
- {
- return -1;
- }
初始化mmap - v4l2_requestbuffers req;
- CLEAR(req);
-
- req.count = 4;
- req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- req.memory = V4L2_MEMORY_MMAP;
-
- if(-1 == ioctl(fd, VIDIOC_REQBUFS, &req))
- {
- if(EINVAL == errno)
- {
- emit display_error(tr("%1 does not support memory mapping").arg(dev_name));
- return -1;
- }
- else
- {
- emit display_error(tr("VIDIOC_REQBUFS %1").arg(QString(strerror(errno))));
- return -1;
- }
- }
-
- if(req.count < 2)
- {
- emit display_error(tr("Insufficient buffer memory on %1").arg(dev_name));
- return -1;
- }
-
- buffers = (buffer*)calloc(req.count, sizeof(*buffers));
-
- if(!buffers)
- {
- emit display_error(tr("out of memory"));
- return -1;
- }
-
- for(n_buffers = 0; n_buffers < req.count; ++n_buffers)
- {
- v4l2_buffer buf;
- CLEAR(buf);
-
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory = V4L2_MEMORY_MMAP;
- buf.index = n_buffers;
-
- if(-1 == ioctl(fd, VIDIOC_QUERYBUF, &buf))
- {
- emit display_error(tr("VIDIOC_QUERYBUF: %1").arg(QString(strerror(errno))));
- return -1;
- }
-
- buffers[n_buffers].length = buf.length;
- buffers[n_buffers].start =
- mmap(NULL,
- buf.length,
- PROT_READ | PROT_WRITE,
- MAP_SHARED,
- fd, buf.m.offset);
-
- if(MAP_FAILED == buffers[n_buffers].start)
- {
- emit display_error(tr("mmap %1").arg(QString(strerror(errno))));
- return -1;
- }
- }
开始捕获视频- int VideoDevice::start_capturing()
- {
- unsigned int i;
- for(i = 0; i < n_buffers; ++i)
- {
- v4l2_buffer buf;
- CLEAR(buf);
-
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf.memory =V4L2_MEMORY_MMAP;
- buf.index = i;
-
-
- if(-1 == ioctl(fd, VIDIOC_QBUF, &buf))
- {
- emit display_error(tr("VIDIOC_QBUF: %1").arg(QString(strerror(errno))));
- return -1;
- }
- }
-
- v4l2_buf_type type;
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- if(-1 == ioctl(fd, VIDIOC_STREAMON, &type))
- {
- emit display_error(tr("VIDIOC_STREAMON: %1").arg(QString(strerror(errno))));
- return -1;
- }
- return 0;
- }
获取一帧图像- int VideoDevice::get_frame(void **frame_buf, size_t* len)
- {
- v4l2_buffer queue_buf;
- CLEAR(queue_buf);
-
- queue_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- queue_buf.memory = V4L2_MEMORY_MMAP;
-
- if(-1 == ioctl(fd, VIDIOC_DQBUF, &queue_buf))
- {
- switch(errno)
- {
- case EAGAIN:
-
- return -1;
- case EIO:
- return -1 ;
- default:
- emit display_error(tr("VIDIOC_DQBUF: %1").arg(QString(strerror(errno))));
- return -1;
- }
- }
-
- *frame_buf = buffers[queue_buf.index].start;
- *len = buffers[queue_buf.index].length;
- index = queue_buf.index;
-
- return 0;
-
- }
获取完后,将这一帧图像的buf放回去- int VideoDevice::unget_frame()
- {
- if(index != -1)
- {
- v4l2_buffer queue_buf;
- CLEAR(queue_buf);
-
- queue_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- queue_buf.memory = V4L2_MEMORY_MMAP;
- queue_buf.index = index;
-
- if(-1 == ioctl(fd, VIDIOC_QBUF, &queue_buf))
- {
- emit display_error(tr("VIDIOC_QBUF: %1").arg(QString(strerror(errno))));
- return -1;
- }
- return 0;
- }
- return -1;
- }
停止视频捕捉- int VideoDevice::stop_capturing()
- {
- v4l2_buf_type type;
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- if(-1 == ioctl(fd, VIDIOC_STREAMOFF, &type))
- {
- emit display_error(tr("VIDIOC_STREAMOFF: %1").arg(QString(strerror(errno))));
- return -1;
- }
- return 0;
- }
卸载摄像头设备- int VideoDevice::uninit_device()
- {
- unsigned int i;
- for(i = 0; i < n_buffers; ++i)
- {
- if(-1 == munmap(buffers[i].start, buffers[i].length))
- {
- emit display_error(tr("munmap: %1").arg(QString(strerror(errno))));
- return -1;
- }
-
- }
- free(buffers);
- return 0;
- }
关闭视频设备文件- int VideoDevice::close_device()
- {
- if(-1 == close(fd))
- {
- emit display_error(tr("close: %1").arg(QString(strerror(errno))));
- return -1;
- }
- return 0;
- }
这就是完整的采集视频的流程,当然可以多增加配置采集的视频格式的代码。 0 0