Linux---Qt5用V4L2读取摄像头,实现实时画面和拍照

平台:ubuntu14.04

工具:qt5.7_opensource版本

Desktop


1. V4L2的介绍:

摘自http://www.cnblogs.com/silence-hust/p/4464291.html

大部分都一样的流程,多看几遍再结合代码就可以看懂的。

一、Video for Linux two

  v4l2为linux下视频设备程序提供了一套接口规范。包括一套数据结构和底层V4L2驱动接口。只能在linux下使用。它使程序有发现设备和操作设备的能力。它主要是用一系列的回调函数来实现这些功能。像设置摄像头的频率、帧频、视频压缩格式和图像参数等等。当然也可以用于其他多媒体的开发,如音频等。

  在Linux下,所有外设都被看成一种特殊的文件,成为“设备文件”,可以象访问普通文件一样对其进行读写。一般来说,采用V4L2驱动的摄像头设备文是/dev/v4l/video0。为了通用,可以建立一个到/dev/video0的链接。V4L2支持两种方式来采集图像:内存映射方式(mmap)和直接读取方式(read)。V4L2在include/linux/videodev.h文件中定义了一些重要的数据结构,在采集图像的过程中,就是通过对这些数据的操作来获得最终的图像数据。Linux系统V4L2的能力可在Linux内核编译阶段配置,默认情况下都有此开发接口。V4L2从Linux 2.5.x版本的内核中开始出现。

  V4L2规范中不仅定义了通用API元素(Common API Elements),图像的格式(Image Formats),输入/输出方法(Input/Output),还定义了Linux内核驱动处理视频信息的一系列接口(Interfaces),这些接口主要有:

  视频采集接口——Video Capture Interface;

  视频输出接口—— Video Output Interface;

  视频覆盖/预览接口——Video Overlay Interface;

  视频输出覆盖接口——Video Output Overlay Interface;

  编解码接口——Codec Interface。

二、v4l2结构体介绍

1、常用的结构体在内核目录include/linux/videodev2.h中定义

        struct v4l2_requestbuffers        //申请帧缓冲,对应命令VIDIOC_REQBUFS 
        struct v4l2_capability        //视频设备的功能,对应命令VIDIOC_QUERYCAP 
        struct v4l2_input        //视频输入信息,对应命令VIDIOC_ENUMINPUT
        struct v4l2_standard        //视频的制式,比如PAL,NTSC,对应命令VIDIOC_ENUMSTD 
        struct v4l2_format        //帧的格式,对应命令VIDIOC_G_FMT、VIDIOC_S_FMT等
        struct v4l2_buffer        //驱动中的一帧图像缓存,对应命令VIDIOC_QUERYBUF 
        struct v4l2_crop        //视频信号矩形边框

        v4l2_std_id        //视频制式


常用结构体的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct  v4l2_capability
 
{
 
u8 driver[16];  // 驱动名字
 
u8 card[32];  // 设备名字
 
u8 bus_info[32];  // 设备在系统中的位置
 
u32 version;  // 驱动版本号
 
u32 capabilities;  // 设备支持的操作
 
u32 reserved[4];  // 保留字段
 
};

  其中域 capabilities 代表设备支持的操作模式,常见的值有 V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING 表示是一个视频捕捉设备并且具有数据流控制模式;另外 driver 域需要和 struct video_device 中的 name 匹配。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
struct  v4l2_format { 
     enum  v4l2_buf_type type; 
     union 
         struct  v4l2_pix_format         pix;      /* V4L2_BUF_TYPE_VIDEO_CAPTURE */ 
         struct  v4l2_window             win;      /* V4L2_BUF_TYPE_VIDEO_OVERLAY */ 
         struct  v4l2_vbi_format         vbi;      /* V4L2_BUF_TYPE_VBI_CAPTURE */ 
         struct  v4l2_sliced_vbi_format  sliced;   /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */ 
         __u8   raw_data[200];                    /* user-defined */ 
     } fmt; 
}; 
 
enum  v4l2_buf_type { 
     V4L2_BUF_TYPE_VIDEO_CAPTURE        = 1, 
     V4L2_BUF_TYPE_VIDEO_OUTPUT         = 2, 
     V4L2_BUF_TYPE_VIDEO_OVERLAY        = 3, 
     ... 
     V4L2_BUF_TYPE_PRIVATE              = 0x80, 
}; 
   
struct  v4l2_pix_format { 
     __u32                   width; 
     __u32                   height; 
     __u32                   pixelformat; 
     enum  v4l2_field         field; 
     __u32                   bytesperline;    /* for padding, zero if unused */ 
     __u32                   sizeimage; 
     enum  v4l2_colorspace    colorspace; 
     __u32                   priv;            /* private data, depends on pixelformat */ 
};

  常见的捕获模式为 V4L2_BUF_TYPE_VIDEO_CAPTURE 即视频捕捉模式,在此模式下 fmt 联合体采用域 v4l2_pix_format:其中 width 为视频的宽、height 为视频的高、pixelformat 为视频数据格式(常见的值有 V4L2_PIX_FMT_YUV422P | V4L2_PIX_FMT_RGB565)、bytesperline 为一行图像占用的字节数、sizeimage 则为图像占用的总字节数、colorspace 指定设备的颜色空间。

 

struct v4l2_requestbuffers 与 VIDIOC_REQBUFS ,VIDIOC_REQBUFS 命令通过结构 v4l2_requestbuffers 请求驱动申请一片连续的内存用于缓存视频信息:

1
2
3
4
5
6
7
8
9
10
11
struct  v4l2_requestbuffers {
     __u32                   count;
     enum  v4l2_buf_type      type;
     enum  v4l2_memory        memory;
     __u32                   reserved[2];
};
enum  v4l2_memory {
     V4L2_MEMORY_MMAP             = 1,
     V4L2_MEMORY_USERPTR          = 2,
     V4L2_MEMORY_OVERLAY          = 3,
};

count 指定根据图像占用空间大小申请的缓存区个数,type 为视频捕获模式,memory 为内存区的使用方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct  v4l2_buffer {
     __u32   index;
     enum  v4l2_buf_type    type;
     __u32    bytesused;
     __u32    flags;
     enum  v4l2_field  field;
     struct  timeval    timestamp;
     struct  v4l2_timecode   timecode;
     __u32     sequence;
  
     /* memory location */
     enum  v4l2_memory    memory;
     union  {
             __u32   offset;
             unsigned  long    userptr;
     } m;
     __u32    length;
     __u32    input;
     __u32    reserved;
};

  index 为缓存编号

  type 为视频捕获模式

  bytesused 为缓存已使用空间大小

  flags 为缓存当前状态(常见值有 V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE,分别代表当前缓存已经映射、缓存可以采集数据、缓存可以提取数据)

  timestamp 为时间戳

  sequence为缓存序号

  memory 为缓存使用方式

  offset 为当前缓存与内存区起始地址的偏移

  length 为缓存大小

  reserved 一般用于传递物理地址值。

  另外 VIDIOC_QBUF 和 VIDIOC_DQBUF 命令都采用结构 v4l2_buffer 与驱动通信:VIDIOC_QBUF 命令向驱动传递应用程序已经处理完的缓存,即将缓存加入空闲可捕获视频的队列,传递的主要参数为 index;VIDIOC_DQBUF 命令向驱动获取已经存放有视频数据的缓存,v4l2_buffer 的各个域几乎都会被更新,但主要的参数也是 index,应用程序会根据 index 确定可用数据的起始地址和范围。

 

2、常用的IOCTL接口命令也在include/linux/videodev2.h中定义

VIDIOC_REQBUFS //分配内存 
        VIDIOC_QUERYBUF         //把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址 
        VIDIOC_QUERYCAP        //查询驱动功能 
        VIDIOC_ENUM_FMT        //获取当前驱动支持的视频格式 
        VIDIOC_S_FMT        //设置当前驱动的频捕获格式 
        VIDIOC_G_FMT        //读取当前驱动的频捕获格式 
        VIDIOC_TRY_FMT        //验证当前驱动的显示格式 
        VIDIOC_CROPCAP        //查询驱动的修剪能力 
        VIDIOC_S_CROP        //设置视频信号的矩形边框 
        VIDIOC_G_CROP        //读取视频信号的矩形边框
        VIDIOC_QBUF        //把数据从缓存中读取出来 
        VIDIOC_DQBUF        //把数据放回缓存队列 
        VIDIOC_STREAMON        //开始视频显示函数 
        VIDIOC_STREAMOFF        //结束视频显示函数 
        VIDIOC_QUERYSTD         //检查当前视频设备支持的标准,例如PAL或NTSC。

三、调用v4l2的工作流程

  打开设备-> 检查和设置设备属性-> 设置帧格式-> 设置一种输入输出方法(缓冲 区管理)-> 循环获取数据-> 关闭设备。

2. qt代码实现

https://download.csdn.net/download/sunny_hu92/10356887


猜你喜欢

转载自blog.csdn.net/sunny_hu92/article/details/79985660