视频采集流程(一)

2 提交 / 0个新回复
最新回复
视频采集流程(一)

4G连网完成后接着要开始视频采集了,网上关于视频采集的资料也很多,这里把我自己做的过程跟大家分享:
一.什么是video4linux2

   video4linux2(简称V4L2),是linux中关于视频设备的内核驱动。在Linux中,视频设备是设备文件,可以像访问普通文件一样对其进行读写,摄像头在/dev/video0。

 

二.一般操作流程(视频设备)

1.打开设备文件。 int fd=open(”/dev/video0″,O_RDWR);

2. 取得设备的capability,看看设备具有什么功能,比如是否具有视频输入,或者音频输入输出等。VIDIOC_QUERYCAP,struct v4l2_capability

3. 选择视频输入,一个视频设备可以有多个视频输入。VIDIOC_S_INPUT,struct v4l2_input

4. 设置视频的制式和帧格式,制式包括PAL,NTSC,帧的格式中包括宽度和高度等。

VIDIOC_S_STD,VIDIOC_S_FMT,structv4l2_std_id,struct v4l2_format

5. 向驱动申请帧缓冲,一般不超过5个。struct v4l2_requestbuffers

6. 将申请到的帧缓冲映射到用户空间,这样就可以直接操作采集到的帧了,而不必去复制。mmap

7. 将申请到的帧缓冲全部入队列,以便存放采集到的数据.VIDIOC_QBUF,struct v4l2_buffer

8. 开始视频的采集。VIDIOC_STREAMON

9. 出队列以取得已采集数据的帧缓冲,取得原始采集数据。VIDIOC_DQBUF

10. 将缓冲重新入队列尾,这样可以循环采集。VIDIOC_QBUF

11. 停止视频的采集。VIDIOC_STREAMOFF

12. 关闭视频设备。close(fd);

 

三.常用的结构体

(参见/usr/include/linux/videodev2.h)

(1) struct v4l2_requestbuffers reqbufs;//向驱动申请帧缓冲的请求,里面包含申请的个数

(2) struct v4l2_capability cap;//这个设备的功能,比如是否是视频输入设备

(3) struct v4l2_input input; //视频输入

     struct v4l2_standard std;//视频的制式,比如PAL,NTSC

(4) struct v4l2_format fmt;//帧的格式,比如宽度,高度等

     struct v4l2_buffer buf;//代表驱动中的一帧

     v4l2_std_id stdid;//视频制式,例如:V4L2_STD_PAL_B

(5) struct v4l2_queryctrl query;//查询的控制

     struct v4l2_control control;//具体控制的值

 

四.相关函数说明

1.打开视频设备在V4L2中,视频设备被看做一个文件。使用open函数打开这个设备:

     // 用非阻塞模式打开摄像头设备

      int cameraFd;

     cameraFd = open(“/dev/video0″, O_RDWR | O_NONBLOCK, 0);

 

     // 如果用阻塞模式打开摄像头设备,上述代码变为:

      cameraFd = open(”/dev/video0″, O_RDWR, 0);

       关于阻塞模式和非阻塞模式:应用程序能够使用阻塞模式或非阻塞模式打开视频设备,如果使用非阻塞模式调用视频设备,即使尚未捕获到信息,驱动依旧会把缓存(DQBUFF)里的东西返回给应用程序。

 

2. 设定属性及采集方式打开视频设备后,可以设置该视频设备的属性,例如裁剪、缩放等。这一步是可选的。在Linux编程中,一般使用ioctl函数来对设备的I/O通道进行管理:

    

    extern int ioctl (int  fd, int cmd, void *parameter) ;

   

    fd:设备描述符,例如刚才用open函数打开视频通道后返回的cameraFd;

    cmd:控制命令。在进行V4L2开发中,一般会用到以下的控制命令

    parameter:控制命令参数,与cmd的取值有关

    这一部分内容很重要,我在下一篇论坛中详细讲解

 

3.  关于视频采集方式操作系统一般把系统使用的内存划分成用户空间和内核空间,分别由应用程序管理和操作系统管理。应用程序可以直接访问内存的地址,而内核空间存放的是供内核访问的代码和数据,用户不能直接访问。v4l2捕获的数据,最初是存放在内核空间的,这意味着用户不能直接访问该段内存,必须通过某些手段来转换地址。一共有三种视频采集方式:使用read、write方式;内存映射方式和用户指针模式。

 

     read、write方式:在用户空间和内核空间不断拷贝数据,占用了大量用户内存空间,效率不高。内存映射方式:把设备里的内存映射到应用程序中的内存控件,直接处理设备内存,这是一种有效的方式。上面的mmap函数就是使用这种方式。用户指针模式:内存片段由应用程序自己分配。这点需要在v4l2_requestbuffers里将memory字段设置成V4L2_MEMORY_USERPTR。

 

4. 处理采集数据:

        V4L2有一个数据缓存,存放req.count数量的缓存数据。数据缓存采用FIFO的方式,当应用程序调用缓存数据时,缓存队列将最先采集到的视频数据缓存送出,并重新采集一张视频数据。这个过程需要用到两个ioctl命令,VIDIOC_DQBUF和VIDIOC_QBUF:

    struct v4l2_buffer buf;

    memset(&buf,0,sizeof(buf));

    buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

    buf.memory=V4L2_MEMORY_MMAP;

    buf.index=0;//读取缓存

    if (ioctl(cameraFd, VIDIOC_DQBUF, &buf) ==-1)

    {

      return -1;

    }

 

5. 关闭视频设备

使用close函数关闭一个视频设备

close(cameraFd);

 

视频采集流程图:

   

说明:

1、打开摄像头:在Linux系统中,一切设备都可以看做是文件,    所以打开摄像头直接使用open()函数即可。

2、初始化设备:主要设置采集视频的帧率、帧格式、帧宽度与高度等信息。

3、开启视频流:开启摄像头的摄像功能,开始视频的采集。

4、开始采集:从摄像头获取一帧图像。

5、保存一帧图片:将获取到的一帧图片保存到缓存中。

6、写入pipe:将缓存中的数据输出到管道,作为视频压缩编码模块的输入。