V4L2+Qt5实现摄像头视频采集以及参数控制
这一段时间在做摄像头控制方面的工作,需要在Linux下实现对摄像头名称和分辨率的获取,同时对亮度、对比度、曝光值等参数进行控制,同时还需要对获取的帧画面进行处理。目前除了图像处理方面,简单的使用V4l2获取设备属性并可以打开摄像头进行参数控制,以及将读取的原始YUYV2帧数据转换为RGB24格式显示在QLabel上都可以实现,今天先在这里做个总结。
1.对于V4l2常用的结构体以及相关的命令符,网上都有很多参考,对照着官网文档慢慢理解也都能顺下来,下边也就放一点自己学习期间的理解,可能还有错误的地方,不过也没时间细看了,放着以后有时间再来完善吧。
-----------------------------------------------------------------------V4L2常用结构体说明----------------------------------------------------------------------
结构体来源:/usr/include/linux/videodev2.h文件。
*************************************************************************************************************************************************
struct v4l2_capability {
__u8 driver[16]; //驱动名称
__u8 card[32]; //设备名称
__u8 bus_info[32]; //总线信息
__u32 version; //驱动版本号
__u32 capabilities; //设备具备的功能
__u32 device_caps; //通过特定设备(节点)访问的功能(不知道用处,网上其它资料没有该字段)
__u32 reserved[3]; //保留字段
};
说明:该结构体常用来获取设备信息,使用VIDIOC_QUERYCAP命令符,包括驱动名、设备名以及版本号等等,其中capabilities成员表示设备支持的操作模式,比如V4L2_CAP_VIDEO_CAPTURE代表着该设备是一个视频捕捉设备,可以通过(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)来判定该设备是否具备改能力。由于V4L2涵盖了各种设备,不只是摄像头设备,不同的设备具备的能力也不一定相同,因此有需要时也可以来判定指定设备的能力。
/* Values for 'capabilities' field */
#define V4L2_CAP_VIDEO_CAPTURE 0x00000001 /* Is a video capture device */
#define V4L2_CAP_VIDEO_OUTPUT 0x00000002 /* Is a video output device */
#define V4L2_CAP_VIDEO_OVERLAY 0x00000004 /* Can do video overlay */
#define V4L2_CAP_VBI_CAPTURE 0x00000010 /* Is a raw VBI capture device */
#define V4L2_CAP_VBI_OUTPUT 0x00000020 /* Is a raw VBI output device */
#define V4L2_CAP_SLICED_VBI_CAPTURE 0x00000040 /* Is a sliced VBI capture device */
#define V4L2_CAP_SLICED_VBI_OUTPUT 0x00000080 /* Is a sliced VBI output device */
#define V4L2_CAP_RDS_CAPTURE 0x00000100 /* RDS data capture */
#define V4L2_CAP_VIDEO_OUTPUT_OVERLAY 0x00000200 /* Can do video output overlay */
#define V4L2_CAP_HW_FREQ_SEEK 0x00000400 /* Can do hardware frequency seek */
#define V4L2_CAP_RDS_OUTPUT 0x00000800 /* Is an RDS encoder */
/* Is a video capture device that supports multiplanar formats */
#define V4L2_CAP_VIDEO_CAPTURE_MPLANE 0x00001000
/* Is a video output device that supports multiplanar formats */
#define V4L2_CAP_VIDEO_OUTPUT_MPLANE 0x00002000
/* Is a video mem-to-mem device that supports multiplanar formats */
#define V4L2_CAP_VIDEO_M2M_MPLANE 0x00004000
/* Is a video mem-to-mem device */
#define V4L2_CAP_VIDEO_M2M 0x00008000
#define V4L2_CAP_TUNER 0x00010000 /* has a tuner */
#define V4L2_CAP_AUDIO 0x00020000 /* has audio support */
#define V4L2_CAP_RADIO 0x00040000 /* is a radio device */
#define V4L2_CAP_MODULATOR 0x00080000 /* has a modulator */
#define V4L2_CAP_SDR_CAPTURE 0x00100000 /* Is a SDR capture device */
#define V4L2_CAP_EXT_PIX_FORMAT 0x00200000 /* Supports the extended pixel format */
#define V4L2_CAP_SDR_OUTPUT 0x00400000 /* Is a SDR output device */
#define V4L2_CAP_READWRITE 0x01000000 /* read/write systemcalls */
#define V4L2_CAP_ASYNCIO 0x02000000 /* async I/O */
#define V4L2_CAP_STREAMING 0x04000000 /* streaming I/O ioctls */
#define V4L2_CAP_DEVICE_CAPS 0x80000000 /* sets device capabilities field */
*************************************************************************************************************************************************
struct v4l2_fmtdesc {
__u32 index; /* Format number */
__u32 type; /* enum v4l2_buf_type */
__u32 flags;
__u8 description[32]; /* Description string */
__u32 pixelformat; /* Format fourcc */
__u32 reserved[4];
};
说明:该结构体是用来获取设备支持的图像格式,通过VIDIOC_ENUM_FMT命令符;index为格式的序号(可以从0开始循环列举),由程序设置;type只能设置为V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_BUF_TYPE_VIDEO_OUTPUT, V4L2_BUF_TYPE_VIDEO_OVERLAY这几个;flags为是否压缩;description保存着对格式的描述,如"YUV 4:2:2";pixelformat使用v4l2_fourcc()宏保存图像格式,#define v4l2_fourcc(a,b,c,d) (((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24)),可以使用 printf("%c%c%c%c\n",fmtdesc.pixelformat&0XFF,(fmtdesc.pixelformat>>8)&0XFF,(fmtdesc.pixelformat>>16)&0XFF,(fmtdesc.pixelformat>>24)&0XFF);来查看格式;reserved保留位,驱动开发时必须要设置为0;
*************************************************************************************************************************************************
struct v4l2_frmsizeenum {
__u32 index; /* Frame size number */
__u32 pixel_format; /* Pixel format */
__u32 type; /* Frame size type the device supports. */
union { /* Frame size */
struct v4l2_frmsize_discrete discrete;
struct v4l2_frmsize_stepwise stepwise;
};
__u32 reserved[2]; /* Reserved space for future use */
};
struct v4l2_frmsize_discrete {
__u32 width; /* Frame width [pixel] */
__u32 height; /* Frame height [pixel] */
};
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] */
};
说明:该结构体使用VIDIOC_ENUM_FRAMESIZES命令来遍历获取设备分辨率。index为用户指定的索引值(最好从0开始);pixel_format需要指定为v4l2_fmtdesc结构体的pixelformat(v4l2_fmtdesc结构体需要先获取一下);type类型只有三种:V4L2_FRMSIZE_TYPE_DISCRETE(UVC设备驱动固定为该类型)、V4L2_FRMSIZE_TYPE_CONTINUOUS以及V4L2_FRMSIZE_TYPE_STEPWISE,具体有什么区别不清楚,不过使用时不需要指定type;discrete和stepwise结构体保存着帧大小的宽和高相关,一般使用discrete来获取分辨率宽和高即可;reserved为保留位;
*************************************************************************************************************************************************
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 */
__u8 raw_data[200]; /* user-defined */
} fmt;
};
说明:该结构体可以使用VIDIOC_G_FMT命令符获取图像格式(如宽和高,YUYV等),使用VIDIOC_S_FMT设置图像格式。type为枚举类型v4l2_buf_type,camera设备需要设置为V4L2_BUF_TYPE_VIDEO_CAPTURE类型;。
*************************************************************************************************************************************************
struct v4l2_pix_format {
__u32 width; //图像宽
__u32 height; //图像高
__u32 pixelformat; //图像颜色编码格式,如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_*) */
__u32 ycbcr_enc; /* enum v4l2_ycbcr_encoding */
__u32 quantization; /* enum v4l2_quantization */
__u32 xfer_func; /* enum v4l2_xfer_func */
};
说明:存储图像信息格式的结构体;field为v4l2_field枚举类型,决定视频扫描图像的顺序,是逐行还是隔行或是其它,具体用处不清楚,用户设置时可能无效;bytesperline文档相邻行最左边像素的距离,但是实际是指每行的字节数;sizeimage图像大小,计算方式为bytesperline*height;colorspace由驱动设定,如V4L2_COLORSPACE_JPEG(7);
*************************************************************************************************************************************************
struct v4l2_cropcap {
__u32 type; /* enum v4l2_buf_type */
struct v4l2_rect bounds;
struct v4l2_rect defrect;
struct v4l2_fract pixelaspect;
};
说明:该结构体使用VIDIOC_CROPCAP命令符查询图像裁切功能。type类型由应用程序设置,只有V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_BUF_TYPE_VIDEO_OUTPUT, V4L2_BUF_TYPE_VIDEO_OVERLAY,和自定义(驱动程序定义)类型的代码V4L2_BUF_TYPE_PRIVATE 及更高版本是有效的;bounds参数为摄像头能捕捉到的窗口大小限制;defrect参数为裁剪大小,默认裁剪整个窗口,可有v4l2_crop结构体来获取或设置当前裁剪窗口大小;pixelaspect参数为宽高比例,驱动里默认为1/1;
*************************************************************************************************************************************************
struct v4l2_crop {
__u32 type; /* enum v4l2_buf_type */
struct v4l2_rect c;
};
说明:该结构体用来获取或设置图像裁剪矩形区域的值。有些设备不支持裁剪设置,可以通过if(ret == -1 && errno != EINVAL) perror("VIDIOC_S_CROP");来进行判断设备该能力。
*************************************************************************************************************************************************
struct v4l2_queryctrl {
__u32 id;
__u32 type; /* enum v4l2_ctrl_type */
__u8 name[32]; /* Whatever */
__s32 minimum; /* Note signedness */
__s32 maximum;
__s32 step;
__s32 default_value;
__u32 flags;
__u32 reserved[2];
};
说明:该结构体是用(VIDIOC_QUERYCTRL, VIDIOC_QUERYMENU)来查询某个id对应的具体参数的;比如查询亮度值可以设置id = V4L2_CID_BRIGHTNESS。在Control IDs列表中第一项为V4L2_CID_BASE,最后一项为V4L2_CID_LASTP1(其实最后为V4L2_CID_PRIVATE_BASE项,不过该项为自定义项),可以通过这两个临界值去遍历该设备所有具备的控制能力。
常用id值:
V4L2_CID_CONTRAST (V4L2_CID_BASE+1) /* 对比度调节 */
V4L2_CID_SATURATION (V4L2_CID_BASE+2) /* 饱和度调节 */
V4L2_CID_AUDIO_VOLUME (V4L2_CID_BASE+5) /* 音量调节 */
V4L2_CID_AUDIO_MUTE (V4L2_CID_BASE+9) /* 静音设置 */
V4L2_CID_DO_WHITE_BALANCE (V4L2_CID_BASE+13) /* 白平衡调节 */
V4L2_CID_GAMMA (V4L2_CID_BASE+16) /* 伽马值调节 */
V4L2_CID_EXPOSURE (V4L2_CID_BASE+17) /* 曝光度调节 */
V4L2_CID_PRIVATE_ATXX_FLASH (V4L2_CID_PRIVATE_BASE + 2) /* 闪光灯控制 */
V4L2_CID_PRIVATE_ATXX_FRAME (V4L2_CID_PRIVATE_BASE + 12) /* 帧率调节 */
type类型:
enum v4l2_ctrl_type {
V4L2_CTRL_TYPE_INTEGER = 1, //整型
V4L2_CTRL_TYPE_BOOLEAN = 2, //布尔型,0代表禁用,1代表启用;
V4L2_CTRL_TYPE_MENU = 3, //菜单,需要VIDIOC_QUERYMENU命令符;
V4L2_CTRL_TYPE_BUTTON = 4, //无值
V4L2_CTRL_TYPE_INTEGER64 = 5, //64位整型
V4L2_CTRL_TYPE_CTRL_CLASS = 6,
V4L2_CTRL_TYPE_STRING = 7,
V4L2_CTRL_TYPE_BITMASK = 8,
V4L2_CTRL_TYPE_INTEGER_MENU = 9,
/* Compound types are >= 0x0100 */
V4L2_CTRL_COMPOUND_TYPES = 0x0100,
V4L2_CTRL_TYPE_U8 = 0x0100,
V4L2_CTRL_TYPE_U16 = 0x0101,
V4L2_CTRL_TYPE_U32 = 0x0102,
};
flags标志:
V4L2_CTRL_FLAG_DISABLED 0×0001 此控件将永久禁用,应由应用程序忽略。任何更改控件的尝试都将导致EINVAL错误代码。
V4L2_CTRL_FLAG_GRABBED 0×0002 该控制暂时不可更改,例如因为另一个应用程序接管了对相应资源的控制。这些控件可以特别在用户界面中显示。尝试更改控件可能会导致 EBUSY错误代码。
V4L2_CTRL_FLAG_READ_ONLY 0x0004 此控件仅可永久读取。任何更改控件的尝试都将导致EINVAL错误代码。
V4L2_CTRL_FLAG_UPDATE ×0008 提示更改此控件可能会影响同一控件类中其他控件的值。应用程序应相应地更新其用户界面。
V4L2_CTRL_FLAG_INACTIVE 0×0010 此控件不适用于当前配置,应在用户界面中相应显示。例如,当用另一个控制选择MPEG音频编码等级1时,可以在MPEG音频等级2比特率控制上设置标志。
V4L2_CTRL_FLAG_SLIDER 0×0020 提示此控件最好表示为用户界面中类似滑块的元素。
V4L2_CTRL_FLAG_WRITE_ONLY 即0x0040 此控件仅可永久写入。任何读取控件的尝试都将导致EACCES错误代码错误代码。该标志通常存在于相对控制或动作控制中,其中写入值将使设备执行给定动作(例如电动机控制),但是不能返回有意义的值。
*************************************************************************************************************************************************
struct v4l2_control {
__u32 id;
__s32 value;
};
说明:该结构体时用来设置或获取某个id的当前值,通过VIDIOC_G_CTRL,VIDIOC_S_CTRL命令符;
*************************************************************************************************************************************************
struct v4l2_requestbuffers {
__u32 count;
__u32 type; /* enum v4l2_buf_type */
__u32 memory; /* enum v4l2_memory */
__u32 reserved[2];
};
说明:该结构体是用来申请缓存区的,使用VIDIOC_REQBUFS命令符来请求buffer。count参数表示要申请的buffer数量,只有当memory被设置为V4L2_MEMORY_MMAP才可以使用;type就不多说了,还是V4L2_BUF_TYPE_VIDEO_CAPTURE类型;memory参数是应用程序设置的,这里只能设置为V4L2_MEMORY_MMAP或V4L2_MEMORY_USERPTR。
*************************************************************************************************************************************************
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;
};
说明:与内存映射相关的结构体,使用VIDIOC_DQBUF或VIDIOC_QBUF命令符来出队或入队一个缓存帧。
*************************************************************************************************************************************************
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;
};
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];
};
struct v4l2_fract {
__u32 numerator;
__u32 denominator;
};
说明:视频流参数的设置,使用VIDIOC_G_PARM或VIDIOC_S_PARM命令符来获取或设置视频流参数,比如获取或设置fps,type为V4L2_BUF_TYPE_VIDEO_CAPTURE,parm使用capture成员,而capture结构体中的timeperframe成员保存着帧率信息,两帧相间周期为numerator/denominator,即每秒有denominator帧(当numerator=1时)。当然实际设置和获取的帧率往往和视频显示的不一致,因为中间数据转换的过程有些耗时以及硬件可能达不到实际的设置值。
*************************************************************************************************************************************************
2.我笔记本电脑摄像头可控制的项有:
-----------------------------------------------------------
index:9963776
type:1
name:Brightness
minimum:0
maximum:255
step:1
default_value:128
flags:0
-----------------------------------------------------------
index:9963777
type:1
name:Contrast
minimum:0
maximum:255
step:1
default_value:32
flags:0
-----------------------------------------------------------
index:9963778
type:1
name:Saturation
minimum:0
maximum:100
step:1
default_value:64
flags:0
-----------------------------------------------------------
index:9963779
type:1
name:Hue
minimum:-180
maximum:180
step:1
default_value:0
flags:0
-----------------------------------------------------------
index:9963788
type:2
name:White Balance Temperature, Auto
minimum:0
maximum:1
step:1
default_value:1
flags:0
-----------------------------------------------------------
index:9963792
type:1
name:Gamma
minimum:90
maximum:150
step:1
default_value:120
flags:0
-----------------------------------------------------------
index:9963800
type:3
name:Power Line Frequency
minimum:0
maximum:2
step:1
default_value:1
flags:0
-----------------------------------------------------------
index:9963802
type:1
name:White Balance Temperature
minimum:2500
maximum:6500
step:10
default_value:4500
flags:16
-----------------------------------------------------------
index:9963803
type:1
name:Sharpness
minimum:0
maximum:7
step:1
default_value:0
flags:0
-----------------------------------------------------------
index:9963804
type:1
name:Backlight Compensation
minimum:0
maximum:2
step:1
default_value:0
flags:0
-----------------------------------------------------------
index:0
type:3
name:Exposure, Auto
minimum:0
maximum:3
step:1
default_value:3
flags:0
-----------------------------------------------------------
index:0
type:1
name:Exposure (Absolute)
minimum:2
maximum:1250
step:1
default_value:156
flags:16
-----------------------------------------------------------
index:0
type:2
name:Exposure, Auto Priority
minimum:0
maximum:1
step:1
default_value:0
flags:0
-----------------------------------------------------------
一般的根据index来获取某一项的具体属性,然后在Qt界面可以使用滚动条来控制具体的数值,最大最小以及步长都有了,还有恢复默认值的default_value值。
3.在学习期间做了个Demo,也打了包,使用V4l2去获取硬件设备的信息,以及控制视频流的打开关闭,各种用户参数和扩展参数的获取和设置,最终将读取的帧画面进行格式转换为Qt支持的格式显示在QLabel上,以下是一些截图,最后在放上打包的程序,至于源码和自己二次封装的库等以后修改差不多了在上传吧。打包后的Demo下载(如何不要下载积分?)