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)存儲。

存儲


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM