zoukankan      html  css  js  c++  java
  • V4L2 API详解 <二> Camera详细设置【转】

    转自:http://blog.sina.com.cn/s/blog_602f87700101bf36.html

    作者: Sam (甄峰)  sam_code@hotmail.com

     
    Camera的可设置项极多,V4L2 支持了不少。但Sam之前对这些设置的用法和涵义都是在看videodev2.h中边看边理解,感觉非常生涩。直到写这篇blog时,才发现v4l2有专门的SPEC来说明:
    http://www.linuxtv.org/downloads/legacy/video4linux/API/V4L2_API/spec-single/v4l2.html
     
    但也基本没有时间仔细看了。先把自己看头文件看出的一些东西记录在这里吧。
     
    以实际设置过程为顺序谈谈V4L2 设置。
     
     
    1. 查询V4L2 功能集:VIDIOC_QUERYCAP
    struct v4l2_capability cap;
    int rel = 0;
    ioctl(Handle, VIDIOC_QUERYCAP, &cap);
     
    使用ioctl VIDIOC_QUERYCAP 来查询当前driver是否合乎规范。因为V4L2要求所有driver 和Device都支持这个Ioctl。 所以,可以通过这个ioctl是否成功来判断当前设备和dirver 是否支持V4L2规范。当然,这样同时还能够得到设备足够的能力信息。
     
    struct v4l2_capability
    {
     __u8 driver[16];   //驱动名。
     __u8 card[32];     // Device名
     __u8 bus_info[32];  //在Bus系统中存放位置
     __u32 version;      //driver 版本
     __u32 capabilities;  //能力集
     __u32 reserved[4];
    };
    能力集中包含:

    V4L2_CAP_VIDEO_CAPTURE 0x00000001     The device supports the Video    Capture interface.

    V4L2_CAP_VIDEO_OUTPUT   0x00000002     The device supports the Video    Output interface.

    V4L2_CAP_VIDEO_OVERLAY 0x00000004     The device supports the Video    Overlay interface.

    A video overlay device typically stores captured images directly in the video memory   of a graphics card,with hardware clipping and scaling.

    V4L2_CAP_VBI_CAPTURE     0x00000010 The device supports the Raw  VBI Capture interface, providing Teletext and Closed Caption   data.

    V4L2_CAP_VBI_OUTPUT     0x00000020      The device supports the Raw  VBI Output interface.

    V4L2_CAP_SLICED_VBI_CAPTURE  0x00000040 The device supports the Sliced VBI Capture interface.

    V4L2_CAP_SLICED_VBI_OUTPUT   0x00000080 The device supports the Sliced VBI Output interface.

    V4L2_CAP_RDS_CAPTURE    0x00000100          [to be defined]

    #define V4L2_CAP_TUNER 0x00010000  
    #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.表示像素格式,我们就研究之。
     
    V4L2_PIX_FMT_RGB565:

    每个像素使用2字节(16bit)存储,其中:

    5bit R,6bit G,5bit B

    存储格式如下所示:

    低字节 高字节

    GGGBBBBB RRRRRGGG

    RGB565色深等于16,可以表示65536种颜色

     
    V4L2_PIX_FMT_RGB24

    每个像素使用3字节(24bit)存储,其中:

    8bit R,8bit G,8bit B

    存储格式如下所示:

    低字节 高字节

    RRRRRRRR GGGGGGGG BBBBBBBB

    RGB24色深等于24,可以表示16777216种颜色。24位色深被称为真彩色,它达到了人眼分辨的极限

     

    V4L2_PIX_FMT_BGR24

    每个像素使用3字节(24bit)存储,其中:

    8bit B,8bit G,8bit R

    存储格式如下所示:

    低字节 高字节

    BBBBBBBB GGGGGGGG RRRRRRRR

    BGR24色深等于24,可以表示16777216种颜色。

     

    YUV的存储格式分两大类:Package(打包)格式和Planar(平面)格式。

    Package格式将Y,U,V数据统一存放在一个数组中,通常是几个相邻的像素组成一个宏像素(macro-pixel).

    Planar格式则是分别使用三个数据存放三个数据。

    V4L2_PIX_FMT_YUV420

    V4L2_PIX_FMT_YUV420属于planar格式,Y、U、V三个分量分别存储在三个平面,使用YUV4:2:0模式进行采样,该采样模式下,水平方向的两个连续像素和垂直方向的两个连续像素,总共四个像素组成一个宏像素,每个像素使用1.5字节(12bit)存储,每个宏像素使用6字节(48bit)存储。

    存储格式如下图所示:

    V4L2 <wbr>API详解 <wbr><二> <wbr> <wbr> <wbr>Camera详细设置

    视频驱动之颜色空间简介

    从上图可知,YUV4:2:0采样时,水平方向的U、V分量会进行2:1的降采样,垂直方向的U、V分量也会进行2:1的降采样,即只采样25%的色度信息,此时U、V分量宽度变为Y分量的1/2,高度也变为Y分量的1/2。

    那么问题来了,Y0、Y1、Y2、Y3和U0、V0是否组成一个宏像素?

    答:不是。

    请看下图,应该是水平方向的两个连续像素和垂直方向的两个连续像素,总共四个像素组成一个宏像素,即Y1、Y2、Y7、Y8和U1、V1组成一个宏像素,Y1、Y2、Y7、Y8共用U1、V1

    V4L2 <wbr>API详解 <wbr><二> <wbr> <wbr> <wbr>Camera详细设置

    V4L2_PIX_FMT_YUYV

    V4L2_PIX_FMT_YUYV属于packed格式,Y、U、V三个分量交叉存储在同一个平面,使用YUV4:2:2模式进行采样,在该采样模式下,

    水平方向的两个连续像素组成一个宏像素,每个像素使用2字节(16bit)存储,每个宏像素使用4字节(32bit)存储。

    存储格式如下所示:

    低字节 高字节

    Y0 U0 Y1 V0 Y2 U1 Y3 V1 Y4 U2 Y5 V2 Y6 U3 Y7 V3

    从上述信息可知:Y0 U0 Y1 V0组成一个宏像素Y0、Y1共用U0和V0

    大多数Camera都提供这种格式。

    V4L2_PIX_FMT_UYVY

    V4L2_PIX_FMT_UYVY属于packed格式,Y、U、V三个分量交叉存储在同一个平面,使用YUV4:2:2模式进行采样,在该采样模式下,

    水平方向的两个连续像素组成一个宏像素,每个像素使用2字节(16bit)存储,每个宏像素使用4字节(32bit)存储。

    存储

  • 相关阅读:
    Sql server 2005 restore failed
    使用Windows Live Writer发布到cnblogs
    IE7 Tab problem
    转: 编码,charset,乱码,unicode,utf8与net简单释义(续)
    移动12.1号动感地带寻宝答案
    转: 各种 lightbox 实现
    Cannot connect windows 2003 server remotely by mstsc
    boost asio 网络编程案例简单改写
    读书笔记之《程序员的自我修养链接、装载与库》
    基于OpenSSL简单实现Shamir基于身份的数字签名算法
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/10102013.html
Copyright © 2011-2022 走看看