#define V4L2_CAP_AUDIO 0x00020000
#define V4L2_CAP_RADIO 0x00040000
#define V4L2_CAP_READWRITE 0x01000000
#define V4L2_CAP_ASYNCIO 0x02000000
#define V4L2_CAP_STREAMING 0x04000000
看起来很熟悉吧,其实就是Driver里面的Type。
__u8 driver[16]; driver名,通常为:uvcvideo
__u8 card[32];
设备名:厂商会填写。
__u8 bus_info[32];
bus,通常为:usb-hiusb-ehci-2.4
__u32 version;
__u32 capabilities;
通常为:V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_STREAMING
__u32 reserved[4];
2. 枚举设备所支持的image format: VIDIOC_ENUM_FMT
struct v4l2_fmtdesc fmtdesc;
fmtdesc.index = 0;
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(Handle, VIDIOC_ENUM_FMT, &fmtdesc);
使用ioctl
VIDIOC_ENUM_FMT 依次询问,type为:V4L2_BUF_TYPE_VIDEO_CAPTURE。
index从0开始,依次增加,直到返回 -1 (如果index有效,则返回0). Driver会填充结构体struct v4l2_fmtdesc的其它内容,如果index超出范围,则返回-1。
struct v4l2_fmtdesc
{
__u32 index;
// 需要填充,从0开始,依次上升。
enum v4l2_buf_type type;
//Camera,则填写V4L2_BUF_TYPE_VIDEO_CAPTURE
__u32 flags;
// 如果压缩的,则Driver 填写:V4L2_FMT_FLAG_COMPRESSED,否则为0
__u8 description[32];
// image format的描述,如:YUV 4:2:2 (YUYV)
__u32 pixelformat;
//所支持的格式。 如:V4L2_PIX_FMT_UYVY
__u32 reserved[4];
};
这样,则知道当前硬件支持什么样的image format. 下一步,则可以设置image 了。当然,设置之前,还可以读取当前缺省设置。
图像格式,见附录1.
3. 得到和设置Image Format: VIDIOC_G_FMT, VIDIOC_S_FMT:
3.1: 得到当前Image Format:
struct v4l2_format Format;
memset(&Format, 0, sizeof(struct v4l2_format));
Format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(Handle, VIDIOC_G_FMT, &Format);
利用ioctl
VIDIOC_G_FMT. 得到当前设置。
因为Camera为CAPTURE设备,所以需要设置type为:
V4L2_BUF_TYPE_VIDEO_CAPTURE
然后Driver会填充其它内容。
struct v4l2_format
{
enum v4l2_buf_type type;
// Camera,则用户必须填写:V4L2_BUF_TYPE_VIDEO_CAPTURE
union
{
struct v4l2_pix_format pix; //
used by video capture and output devices
struct v4l2_window win;
struct v4l2_vbi_format vbi;
struct v4l2_sliced_vbi_format sliced;
__u8 raw_data[200];
} fmt;
};
因为是Camera, 所以采用pix. 现在分析如下:
struct v4l2_pix_format
{
__u32 width;
//Image width in pixels.
__u32 height;
// Image Height in pixels.
__u32 pixelformat;
// Image格式,最常见的有:V4L2_PIX_FMT_YYUV
enum v4l2_field field; //是否逐行扫描,是否隔行扫描. Sam通常采用V4L2_FIELD_NONE,逐行放置数据
(注1)
__u32 bytesperline; //每行的byte数
__u32 sizeimage;
//总共的byte数,
bytesperline *
height
enum v4l2_colorspace colorspace;
//This information supplements the
pixelformat
and must be set by the driver
__u32 priv;
};
3.2:设置Image Format:VIDIOC_S_FMT
之前通过
VIDIOC_ENUM_FMT已经知道Device支持什么Format。 所以就不用猜测了,直接设置吧。
设置Image
Format ,利用 iocto VIDIOC_S_FMT.
需要APPLICATION填写的Struct项目有:
struct v4l2_format Format;
Format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
Format.fmt.pix.width =
Width;
Format.fmt.pix.height = Height;
Format.fmt.pix.pixelformat= pixelformat;//V4L2_PIX_FMT_YUYV;
Format.fmt.pix.field = field;
io_rel = ioctl(Handle, VIDIOC_S_FMT, &Format);
SamInfo:之前设置了Image Format, 是指每一帧的数据格式,但Stream的行为呢,也需要设置,这就是下面所说的Stream 设置了。它就包含帧数设置和修改。
4. 得到和设置Stream信息:VIDIOC_G_PARM, VIDIOC_S_PARM
Stream信息,主要是设置帧数。
4.1:得到Stream信息:
struct v4l2_streamparm Stream_Parm;
memset(&Stream_Parm, 0, sizeof(struct v4l2_streamparm));
Stream_Parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
io_rel = ioctl(Handle, VIDIOC_G_PARM, &Stream_Parm);
用户只需要填充type为V4L2_BUF_TYPE_VIDEO_CAPTURE。 Driver就会把结构体中其它部分填充好。
struct v4l2_streamparm
{
enum v4l2_buf_type type;
union
{
struct v4l2_captureparm capture;
struct v4l2_outputparm output;
__u8 raw_data[200];
} parm;
};
因为是Camera, 所以使用capture. 它是
struct v4l2_captureparm
struct v4l2_captureparm
{
__u32 capability;
//是否可以被timeperframe控制帧数。可以则:V4L2_CAP_TIMEPERFRAME
__u32 capturemode;
//是否为高清模式。如果是:
则设置为:V4L2_MODE_HIGHQUALITY。 高清模式会牺牲其它信息。通常设置为0。 |
struct v4l2_fract timeperframe;
//帧数。
__u32 extendedmode;
//定制的。如果不支持,设置为0
__u32 readbuffers;
__u32 reserved[4];
};
struct v4l2_fract timeperframe;
//帧数。
struct v4l2_fract {
__u32 numerator;
// 分子。 例:1
__u32 denominator; //分母。 例:30
};
4.2:设置帧数:
struct v4l2_streamparm Stream_Parm;
memset(&Stream_Parm, 0, sizeof(struct v4l2_streamparm));
Stream_Parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
Stream_Parm.parm.capture.timeperframe.denominator =Denominator;;
Stream_Parm.parm.capture.timeperframe.numerator = Numerator;
io_rel = ioctl(Handle, VIDIOC_S_PARM, &Stream_Parm);
请注意,哪怕ioctl返回0。也有可能没设置成功。所以需要再次Get。
当然,哪怕Get发现设置成功。真正抓帧也可能没那么高。
5. 利用VIDIOC_G_CTRL得到一些设置:
一些具体的设置,如曝光模式(Exposure Type),曝光值(Exposure),增益(Gain),白平衡(WHITE_BALANCE),亮度(BRIGHTNESS),饱和度(SATURATION),对比度(CONTRAST)等信息。可以通过VIDIOC_G_CTRL得到当前值。
用法:APP 填写结构体中的id. 通过调用VIDIOC_G_CTRL,driver 会填写结构体中value项。
struct v4l2_control ctrl;
struct v4l2_control
{
__u32 id;
__s32 value;
};
以曝光模式,曝光,和增益为例;
曝光模式:
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_EXPOSURE_AUTO;
ret = ioctl(Handle, VIDIOC_G_CTRL, &ctrl);
ctrl.value 则由Driver填写。告知当前曝光模式。
有以下几个选择:
enum
v4l2_exposure_auto_type {
V4L2_EXPOSURE_AUTO = 0,
V4L2_EXPOSURE_MANUAL = 1,
V4L2_EXPOSURE_SHUTTER_PRIORITY = 2,
V4L2_EXPOSURE_APERTURE_PRIORITY = 3
};
exposure_auto (menu) : min=0 max=3 default=3 value=3
V4L2_CID_EXPOSURE_AUTO |
enum v4l2_exposure_auto_type |
|
|
Enables automatic adjustments of the exposure time and/or iris aperture. The effect of manual changes of the exposure time or iris aperture while these features are enabled is undefined, drivers should ignore such requests. Possible values are: |
|
V4L2_EXPOSURE_AUTO |
Automatic exposure time, automatic iris aperture. |
V4L2_EXPOSURE_MANUAL |
Manual exposure time, manual iris. |
V4L2_EXPOSURE_SHUTTER_PRIORITY |
Manual exposure time, auto iris. |
V4L2_EXPOSURE_APERTURE_PRIORITY |
Auto exposure time, manual iris. |
|
注意: Sam测试发现,在Linux下,V4L2_EXPOSURE_ATUO并不被Firmware认可,要设置自动曝光,需要设置为:
V4L2_EXPOSURE_APERTURE_PRIORITY
曝光:
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_EXPOSURE_ABSOLUTE;
ret = ioctl(Handle, VIDIOC_G_CTRL, &ctrl);
同样,driver填写ctrl.value. 内容为曝光值。
增益:
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_GAIN;
ret = ioctl(Handle, VIDIOC_G_CTRL, &ctrl);
同样,driver填写ctrl.value. 内容为增益。
6. 利用VIDIOC_QUERYCTRL 得到设置具体信息:
在很多情况下,我们并不知道如何设置一些信息,例如,曝光应该设置为多少?Driver能够接受的范围是多少?最大,最小值是多少?步长是多少?缺省值为多少?
可以通过VIDIOC_QUERYCTRL得到。
咱们还是以增益为例:
struct v4l2_queryctrl
Setting;
Setting.id = V4L2_CID_GAIN;
ret = ioctl(Handle, VIDIOC_QUERYCTRL, &Setting);
Driver就会填写结构体中所有信息。
struct v4l2_queryctrl
{
__u32 id;
//用户设置。指定查找的是哪个ID。
enum v4l2_ctrl_type type;
__u8 name[32];
//ID对应的名字。
__s32 minimum;
__s32 maximum;
__s32 step;
//步长
__s32 default_value;
__u32 flags;
__u32 reserved[2];
};
这样,就知道设置什么值是合法的了。那么,下一步就是设置了。
7. 利用VIDIOC_S_CTRL来设置:
很简单,设置id和value.调用ioctl就好。
还是以增益为例:
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_GAIN;
ctrl.value = Gain;
ret = ioctl(Handle, VIDIOC_S_CTRL, &ctrl);
有时候,硬件设置很奇怪,可以设置某个信息,却无法得到如何设置的信息。例如:HD-500可以设置增益。却无法得到该如何设置。
8. 利用扩展Ctrl设置:
焦距(FOUCE);
注1:enum v4l2_field field; 详解:
附录1:
V4L2中像素格式:
在videodev2.h中,结构体 v4l2_format中,包含结构体:v4l2_pix_format,
其中包含pixelformat.表示像素格式,我们就研究之。