zoukankan      html  css  js  c++  java
  • Linux下实现视频读取(二)---camera參数设定

    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開始。依次添加,直到返回. 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 了。当然。设置之前,还能够读取当前缺省设置。



    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
    };
    曝光:
    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来设置:
    非常easy,设置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; 具体解释:

    9.设定分辨率:

    struct v4l2_control control;

    memset(&control, 0, sizeof(control));
    control.id = V4L2_CID_AUTO_WHITE_BALANCE;
    control.value = 1;
    if (ioctl(fd, VIDIOC_S_CTRL, &control) < 0) 
    {
    printf("Couldn't set auto white balance! ");
    //return -1;
    }

    memset(&control, 0, sizeof(control));
    control.id = V4L2_CID_EXPOSURE_AUTO;
    control.value = 1;

    if (ioctl(fd, VIDIOC_S_CTRL, &control) < 0) 
    {
    printf("Couldn't set auto exposure! ");
    //return -1;
    }

    memset(&control, 0, sizeof(control));
    control.id = V4L2_CID_HFLIP;
    control.value = 1;
    if (ioctl(fd, VIDIOC_S_CTRL, &control) < 0) 
    {
    printf("Couldn't set h flip! ");
    //return -1;
    }


    memset(&control, 0, sizeof(control));
    control.id = V4L2_CID_VFLIP;
    control.value = 1;
    if (ioctl(fd, VIDIOC_S_CTRL, &control) < 0) 
    {
    printf("Couldn't set v flip! ");
    //return -1;
    }
  • 相关阅读:
    jython resources
    Installing a Library of Jython ScriptsPart of the WebSphere Application Server v7.x Administration Series Series
    jython好资料
    ulipad install on 64bit win7 has issue
    an oracle article in high level to descibe how to archtichre operator JAVA relevet project
    table的宽度,单元格内换行问题
    Linux常用命令大全
    dedecms系统后台登陆提示用户名密码不存在
    登录织梦后台提示用户名不存在的解决方法介绍
    Shell常用命令整理
  • 原文地址:https://www.cnblogs.com/blfshiye/p/5151167.html
Copyright © 2011-2022 走看看