v4l2编程

一、v4l2基础

V4l2是V4L的升级版本,为linux下视频设备程序提供了一套接口规范。包括一套数据结构和底层V4L2驱动接口。在Linux中,视频设备是设备文件,可以像访问普通文件一样对其进行读写,摄像头在/dev/video0下。

经典例程:https://linuxtv.org/downloads/legacy/video4linux/API/V4L2_API/v4l2spec/capture.c

二、v4l2工具

常用的命令行工具v4l2-ctl在包v4l-utils中,可通过sudo apt install v4l-utils安装。

# 通过v4l2查看摄像头设备

$ sudo v4l2-ctl --list-devices

# 查看当前摄像头支持的视频格式、分辨率和帧速率

$ sudo v4l2-ctl -d /dev/video0 --list-formats

$ sudo v4l2-ctl -d /dev/video0 --list-formats-ext

# 查看摄像头所有参数

$ sudo v4l2-ctl -d  /dev/video0 --all

# 查看摄像头所支持的分辨率

 sudo v4l2-ctl --list-framesizes=MJPG -d /dev/video0

#设置

v4l2-ctl --set-parm=30

v4l2-ctl --set-fmt-video=width=320,height=240,pixelformat=YUYV

$ v4l2-ctl help
unknown arguments: help 

General/Common options:
  --all              display all information available
  -C, --get-ctrl=<ctrl>[,<ctrl>...]
                     get the value of the controls [VIDIOC_G_EXT_CTRLS]
  -c, --set-ctrl=<ctrl>=<val>[,<ctrl>=<val>...]
                     set the value of the controls [VIDIOC_S_EXT_CTRLS]
  -D, --info         show driver info [VIDIOC_QUERYCAP]
  -d, --device=<dev> use device <dev> instead of /dev/video0
                     if <dev> starts with a digit, then /dev/video<dev> is used
  -e, --out-device=<dev> use device <dev> for output streams instead of the
                     default device as set with --device
                     if <dev> starts with a digit, then /dev/video<dev> is used
  -h, --help         display this help message
  --help-all         all options
  --help-io          input/output options
  --help-misc        miscellaneous options
  --help-overlay     overlay format options
  --help-sdr         SDR format options
  --help-selection   crop/selection options
  --help-stds        standards and other video timings options
  --help-streaming   streaming options
  --help-tuner       tuner/modulator options
  --help-vbi         VBI format options
  --help-vidcap      video capture format options
  --help-vidout      vidout output format options
  --help-edid        edid handling options
  -k, --concise      be more concise if possible.
  -l, --list-ctrls   display all controls and their values [VIDIOC_QUERYCTRL]
  -L, --list-ctrls-menus
             display all controls and their menus [VIDIOC_QUERYMENU]
  -r, --subset=<ctrl>[,<offset>,<size>]+
                     the subset of the N-dimensional array to get/set for control <ctrl>,
                     for every dimension an (<offset>, <size>) tuple is given.
  -w, --wrapper      use the libv4l2 wrapper library.
  --list-devices     list all v4l devices
  --log-status       log the board status in the kernel log [VIDIOC_LOG_STATUS]
  --get-priority     query the current access priority [VIDIOC_G_PRIORITY]
  --set-priority=<prio>
                     set the new access priority [VIDIOC_S_PRIORITY]
                     <prio> is 1 (background), 2 (interactive) or 3 (record)
  --silent           only set the result code, do not print any messages
  --sleep=<secs>     sleep <secs>, call QUERYCAP and close the file handle
  --verbose          turn on verbose ioctl status reporting

三、常用数据结构

常用的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_ENUM_FRAMESIZES //枚举设备支持的分辨率信息
VIDIOC_ENUM_FRAMEINTERVALS //获取设备支持的帧间隔
VIDIOC_G_PARM  //获取视频流参数(频率等)
VIDIOC_S_PARM  //设定视频流参数(频率等)
VIDIOC_CROPCAP //查询驱动的修剪能力
VIDIOC_S_CROP //设置视频信号的矩形边框
VIDIOC_G_CROP //读取视频信号的矩形边框
VIDIOC_QBUF //把数据从缓存中读取出来
VIDIOC_DQBUF //把数据放回缓存队列
VIDIOC_STREAMON //开始视频显示函数
VIDIOC_STREAMOFF //结束视频显示函数
VIDIOC_QUERYSTD //检查当前视频设备支持的标准,例如PAL或NTSC。

常用的结构体在系统目录/usr/include/linux/videodev2.h。

struct v4l2_requestbuffers //申请帧缓冲,对应命令VIDIOC_REQBUFS    memory-mapping buffers
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_fmtdesc //帧的格式描述,对应命令VIDIOC_ENUM_FMT等
struct v4l2_buffer //驱动中的一帧图像缓存信息,对应命令VIDIOC_QUERYBUF
struct v4l2_crop //视频信号矩形边框
struct v4l2_cropcap //设置摄像头的捕捉能力,在捕捉视频时应先设置
typedef __u64 v4l2_std_id //视频制式

重要数据结构详情

/*
 *  F O R M A T   E N U M E R A T I O N
 */
struct v4l2_fmtdesc {
    __u32           index;             /* Format number,应用程序设置*/
    __u32           type;              /* enum v4l2_buf_type,帧类型*/
    __u32               flags;         /*是否为压缩格式*/
    __u8            description[32];   /* 格式名称描述 */
    __u32           pixelformat;       /* Format fourcc,格式*/
    __u32           reserved[4];
};
#define V4L2_FMT_FLAG_COMPRESSED 0x0001
#define V4L2_FMT_FLAG_EMULATED   0x0002

所有的视频格式可以能下面的方法查看

#define v4l2_fourcc(a, b, c, d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))

/*
 *  V I D E O   I M A G E   F O R M A T
 */
struct v4l2_pix_format {
    __u32               width;
    __u32           height;
    __u32           pixelformat; //帧格式 V4L2_PIX_FMT_MJPEG  V4L2_PIX_FMT_YUYV
    __u32           field;      /* enum v4l2_field */
    __u32               bytesperline;   /* for padding, zero if unused */
    __u32               sizeimage;
    __u32           colorspace; /* enum v4l2_colorspace */
    __u32           priv;       /* private data, depends on pixelformat */
    __u32           flags;      /* format flags (V4L2_PIX_FMT_FLAG_*) */
    union {
        /* enum v4l2_ycbcr_encoding */
        __u32           ycbcr_enc;
        /* enum v4l2_hsv_encoding */
        __u32           hsv_enc;
    };
    __u32           quantization;   /* enum v4l2_quantization */
    __u32           xfer_func;  /* enum v4l2_xfer_func */
};
/**
 * struct v4l2_format - stream data format
 * @type:   enum v4l2_buf_type; type of the data stream
 * @pix:    definition of an image format
 * @pix_mp: definition of a multiplanar image format
 * @win:    definition of an overlaid image
 * @vbi:    raw VBI capture or output parameters
 * @sliced: sliced VBI capture or output parameters
 * @raw_data:   placeholder for future extensions and custom formats
 */
struct v4l2_format {
    __u32    type;    /*帧类型,应用程序设置 */
    union {
        struct v4l2_pix_format      pix;     /* V4L2_BUF_TYPE_VIDEO_CAPTURE, 使用设备使用*/
        struct v4l2_pix_format_mplane   pix_mp;  /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
        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 */
        struct v4l2_sdr_format      sdr;     /* V4L2_BUF_TYPE_SDR_CAPTURE */
        struct v4l2_meta_format     meta;    /* V4L2_BUF_TYPE_META_CAPTURE */
        __u8    raw_data[200];                   /* user-defined */
    } fmt;
};
/**
  * struct v4l2_capability - Describes V4L2 device caps returned by VIDIOC_QUERYCAP
  *
  * @driver:       name of the driver module (e.g. "bttv")
  * @card:     name of the card (e.g. "Hauppauge WinTV")
  * @bus_info:     name of the bus (e.g. "PCI:" + pci_name(pci_dev) )
  * @version:      KERNEL_VERSION
  * @capabilities: capabilities of the physical device as a whole
  * @device_caps:  capabilities accessed via this particular device (node)
  * @reserved:     reserved fields for future extensions
  */
struct v4l2_capability {
    __u8    driver[16];    //驱动名
    __u8    card[32];      //设备名
    __u8    bus_info[32];  //设备在系统中的位置
    __u32   version;       //驱动版本号
    __u32   capabilities;  //支持的操作 V4L2_CAP_VIDEO_CAPTURE, V4L2_CAP_STREAMING
    __u32   device_caps;   //设备能力
    __u32   reserved[3];
};
/*
 *  M E M O R Y - M A P P I N G   B U F F E R S
 */
struct v4l2_requestbuffers {
    __u32           count;
    __u32           type;       /* enum v4l2_buf_type */
    __u32           memory;     /* enum v4l2_memory */
    __u32           reserved[2];
};
/**
 * struct v4l2_buffer - video buffer info
 * @index:  id number of the buffer
 * @type:   enum v4l2_buf_type; buffer type (type == *_MPLANE for
 *      multiplanar buffers);
 * @bytesused:  number of bytes occupied by data in the buffer (payload);
 *      unused (set to 0) for multiplanar buffers
 * @flags:  buffer informational flags
 * @field:  enum v4l2_field; field order of the image in the buffer
 * @timestamp:  frame timestamp
 * @timecode:   frame timecode
 * @sequence:   sequence count of this frame
 * @memory: enum v4l2_memory; the method, in which the actual video data is
 *      passed
 * @offset: for non-multiplanar buffers with memory == V4L2_MEMORY_MMAP;
 *      offset from the start of the device memory for this plane,
 *      (or a "cookie" that should be passed to mmap() as offset)
 * @userptr:    for non-multiplanar buffers with memory == V4L2_MEMORY_USERPTR;
 *      a userspace pointer pointing to this buffer
 * @fd:     for non-multiplanar buffers with memory == V4L2_MEMORY_DMABUF;
 *      a userspace file descriptor associated with this buffer
 * @planes: for multiplanar buffers; userspace pointer to the array of plane
 *      info structs for this buffer
 * @length: size in bytes of the buffer (NOT its payload) for single-plane
 *      buffers (when type != *_MPLANE); number of elements in the
 *      planes array for multi-plane buffers
 *
 * Contains data exchanged by application and driver using one of the Streaming
 * I/O methods.
 */
struct v4l2_buffer {
    __u32           index;
    __u32           type;
    __u32           bytesused;
    __u32           flags;
    __u32           field;
    struct timeval      timestamp;
    struct v4l2_timecode    timecode;
    __u32           sequence;

    /* memory location */
    __u32           memory;
    union {
        __u32           offset;
        unsigned long   userptr;
        struct v4l2_plane *planes;
        __s32       fd;
    } m;
    __u32           length;
    __u32           reserved2;
    __u32           reserved;
};

视频流参数

struct v4l2_fract {
    __u32   numerator;
    __u32   denominator;
};
struct v4l2_captureparm {
    __u32          capability;    /*  Supported modes */
    __u32          capturemode;   /*  Current mode */
    struct v4l2_fract  timeperframe;  /*  Time per frame in seconds */
    __u32          extendedmode;  /*  Driver-specific extensions */
    __u32              readbuffers;   /*  # of buffers for read */
    __u32          reserved[4];
};

/*  Flags for 'capability' and 'capturemode' fields */
#define V4L2_MODE_HIGHQUALITY   0x0001  /*  High quality imaging mode */
#define V4L2_CAP_TIMEPERFRAME   0x1000  /*  timeperframe field is supported */

struct v4l2_outputparm {
    __u32          capability;   /*  Supported modes */
    __u32          outputmode;   /*  Current mode */
    struct v4l2_fract  timeperframe; /*  Time per frame in seconds */
    __u32          extendedmode; /*  Driver-specific extensions */
    __u32              writebuffers; /*  # of buffers for write */
    __u32          reserved[4];
};
/*  Stream type-dependent parameters
 */
struct v4l2_streamparm {
    __u32    type;          /* enum v4l2_buf_type */
    union {
        struct v4l2_captureparm capture;
        struct v4l2_outputparm  output;
        __u8    raw_data[200];  /* user-defined */
    } parm;
};

帧分辨率

VIDIOC_ENUM_FRAMESIZES:针对VIDIOC_ENUM_FMT所列出的图像格式信息,列举某一格式所对应的分辨率信息。

v4l2_frmsizeenum->type可能有三种情况:

V4L2_FRMSIZE_TYPE_DISCRETE: 可以递增的设置v4l2_frmsizeenum->index来重复调用直到返回EINVAL来获取该种图像格式下所有支持的分辨率. 此时, 可以通过v4l2_frmsizeenum->width和height来获取支持的分辨率的长宽。

V4L2_FRMSIZE_TYPE_STEPWISE: 此时只有v4l2_frmsizeenum->stepwise是有效的, 并且不能再将index设为其他值重复调用此ioctl。

V4L2_FRMSIZE_TYPE_CONTINUOUS: STEPWISE的一种特殊情况, 此时同样只有stepwise有效, 并且stepwise.step_width和stepwise.step_height都为1。

int ioctl( int fd, int request, struct v4l2_frmsizeenum *arg);
struct v4l2_frmsizeenum
{
  __u32 index;            //IN:index of the given frame size in the enumeration
  __u32 pixel_format;        //IN:pixel format for which the frame sizes are enumerated
  __u32 type;                //OUT: frame size type the device supports
  union                    //OUT: frame size with the given index
  {
    struct v4l2_frmsize_discrete  discrete;
    struct v4l2_frmsize_stepwise  stepwise;
  };
  __u32 reserved[2];            
};

struct v4l2_frmsize_discrete
{
  __u32    width;        
  __u32    height;
};

struct v4l2_frmsize_stepwise
{
  __u32    min_width;        //minimum frame width[pixel]
  __u32    max_width;        //maximum frame width[pixel]
  __u32    step_width;        //frame width step size[pixel]
  __u32    min_height;        //minimum frame height[pixel]
  __u32    max_height;        //maximum frame height[pixel]
  __u32    step_height;    //frame height step size[pixel]
};

Video

Video的帧可区分为隔行和逐行:逐行顺序的传输一帧所有的行,而隔行则把一帧划分成两个fields,分别保存帧的奇数行和偶数行,被称作奇场和偶场

所有的video captureout devices必须汇报当前的field顺序。一些驱动可能允许选择不同的序,终端应用可以在调用VIDIOC_S_FMT前初始化struct v4l2_pix_formatfield成员,否则可以使用V4L2_FIELD_ANY

V4L2_FIELD_ANY

0

Application 可以请求使用这个参数,如果V4L2_FIELD_NONE, V4L2_FIELD_TOP, V4L2_FIELD_BOTTOMV4L2_FIELD_INTERLACE 中任何一个格式都支持.驱动选择使用哪一个格式依赖于硬件能力,以及请求的image尺寸,驱动选择一个然后返回这个格式。struct_bufferfield成员不可以为V4L2_FIELD_ANY

V4L2_FIELD_NONE

1

Images是逐行格式,当驱动无法区分V4L2_FIELD_TOPV4L2_FIELD_BOTTOM,可以使用这种field类型

V4L2_FIELD_TOP

2

Images仅仅包含top field

V4L2_FIELD_BOTTOM

3

Images仅仅包含bottom field,应用可能希望防止设备捕获interlaced的图片,因为这种图片会在运动物体周围产生毛状特效

V4L2_FIELD_INTERLACED

4

Images包含topbottom field, 隔行交替,场序依赖于当前video的标准。NTSC首先传输bottom field, PAL则先传输top field

V4L2_FIELD_SEQ_TB

5

Images包含topbottom field, top field的行首先存放在memory中,然后紧跟着bottom field的行。 Fields一直以瞬间序存储,较老的放在内存前面。Images的尺寸和帧相关,而不是field

 

V4L2_FIELD_SEQ_BT

6

Images包含topbottom field, bottom field的行首先存放在memory中,然后紧跟着top field的行。 Fields一直以瞬间序存储,较老的放在内存前面。Images的尺寸和帧相关,而不是field

V4L2_FIELD_ALTERATE

7

 一个帧的两个field分别放在不同的buffer, 按照瞬间序,也就是说老的一个是第一个。driver或者应用指明field的奇偶性(奇偶性:当前的fieldtop 还是bottom field. 任何两个连续的field构成一个frame,是否两个field是连续的,不需要drop掉他们,可以通过v4l2_buffer中的sequence 成员判定。Images的尺寸和frame相关而不是fields相关

V4L2_FIELD_INTERLACED_TB

8

Images 包含topbottom field, 每行交替, top field在前面。top field首先传送

V4L2_FIELD_INTERLACED_BT

9

Images 包含topbottom field, 每行交替, bottom field在前面。bottom field首先传送

四、采集流程

打开设备->获取和设置设备属性->设置输出输入->(申请缓冲及缓冲管理)->获取数据->关闭设备。

注:各类VIDIOC命令相关的ioctl接口函数返回值 ret,若小于零,则表示函数调用失败,若等于零,表示成功执行。

应用程序和设备有三种交换数据的方法,直接read/write、内存映射(mmap)和用户指针,一般采用内存映射方式。

  1. Open设备文件;
  2. 获取设备能力:VIDIOC_QUERYCAP;
  3. 枚举设备支持的视频格式:VIDIOC_ENUM_FMT;
  4. 设置捕获视频格式:VIDIOC_S_FMT,VIDIOC_G_FMT;
  5. 设置视频流信息:VIDIOC_S_PARM,VIDIOC_G_PARM;
  6. 向驱动申请帧缓存,一般不超过5个:VIDIOC_REQBUFS;申请的帧缓存位于内核空间,应用程序需要mmap访问。
  7. 获取每个缓存信息并映射(mmap)到用户空间:VIDIOC_QUERYBUF;将所有缓存放入视频采集队列:VIDIOC_QBUF。
  8. 开启视频采集:VIDIOC_STREAMON;
  9. 取出帧缓存:VIDIOC_DQBUF;处理数据;把处理后的帧缓存放入队列尾:VIDIOC_QBUF;如此循环。
  10. 停止采集:VIDIOC_STREAMOFF;
  11. 取出帧缓存:VIDIOC_DQBUF;解除映射munmap;关闭设备。

注:在驱动程序处理视频的过程中,定义了两个队列:视频采集输入队列(incoming queues)和视频采集输出队列(outgoing queues),前者是等待驱动存放视频数据的队列,后者是驱动程序已经放入了视频数据的队列。

 

参考:

1. https://www.linuxtv.org/downloads/legacy/video4linux/API/V4L2_API/spec-single/v4l2.html 官方API

2. https://linuxtv.org/downloads/v4l-dvb-apis/index.html

3. V4L2采集视频https://notes.z-dd.net/

4. V4L2开发应用流程的各类超实用VIDIOC命令及其结构体集锦

5. (原创)基于ZedBoardWebcam设计()USB摄像头(V4L2接口)的图片采集   超群天晴

6. Uvc设备

7. v4l2_field理解

8. Linux USB摄像头使用简书

9. 基于v4l2的视频驱动开发华清远见

10. v4l2的学习建议和流程解析

11. 视频编码 v4l2 摄像头 图像处理  Biao csdn  li_wen01

12. V4L2摄像头概述 - 百问网嵌入式Linux wiki

posted @ 2016-10-24 22:15  yuxi_o  阅读(8158)  评论(0编辑  收藏  举报