這一段時間在做攝像頭控制方面的工作,需要在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涵蓋了各種裝置,不隻是攝像頭裝置,不同的裝置具備的能力也不一定相同,是以有需要時也可以來判定指定裝置的能力。
#define V4L2_CAP_VIDEO_CAPTURE 0x00000001
#define V4L2_CAP_VIDEO_OUTPUT 0x00000002
#define V4L2_CAP_VIDEO_OVERLAY 0x00000004
#define V4L2_CAP_VBI_CAPTURE 0x00000010
#define V4L2_CAP_VBI_OUTPUT 0x00000020
#define V4L2_CAP_SLICED_VBI_CAPTURE 0x00000040
#define V4L2_CAP_SLICED_VBI_OUTPUT 0x00000080
#define V4L2_CAP_RDS_CAPTURE 0x00000100
#define V4L2_CAP_VIDEO_OUTPUT_OVERLAY 0x00000200
#define V4L2_CAP_HW_FREQ_SEEK 0x00000400
#define V4L2_CAP_RDS_OUTPUT 0x00000800
#define V4L2_CAP_VIDEO_CAPTURE_MPLANE 0x00001000
#define V4L2_CAP_VIDEO_OUTPUT_MPLANE 0x00002000
#define V4L2_CAP_VIDEO_M2M_MPLANE 0x00004000
#define V4L2_CAP_VIDEO_M2M 0x00008000
#define V4L2_CAP_TUNER 0x00010000
#define V4L2_CAP_AUDIO 0x00020000
#define V4L2_CAP_RADIO 0x00040000
#define V4L2_CAP_MODULATOR 0x00080000
#define V4L2_CAP_SDR_CAPTURE 0x00100000
#define V4L2_CAP_EXT_PIX_FORMAT 0x00200000
#define V4L2_CAP_SDR_OUTPUT 0x00400000
#define V4L2_CAP_READWRITE 0x01000000
#define V4L2_CAP_ASYNCIO 0x02000000
#define V4L2_CAP_STREAMING 0x04000000
#define V4L2_CAP_DEVICE_CAPS 0x80000000
*************************************************************************************************************************************************
struct v4l2_fmtdesc {
__u32 index;
__u32 type;
__u32 flags;
__u8 description[32];
__u32 pixelformat;
__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;
__u32 pixel_format;
__u32 type;
union {
struct v4l2_frmsize_discrete discrete;
struct v4l2_frmsize_stepwise stepwise;
};
__u32 reserved[2];
};
struct v4l2_frmsize_discrete {
__u32 width;
__u32 height;
};
struct v4l2_frmsize_stepwise {
__u32 min_width;
__u32 max_width;
__u32 step_width;
__u32 min_height;
__u32 max_height;
__u32 step_height;
};
說明:該結構體使用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;
struct v4l2_pix_format_mplane pix_mp;
struct v4l2_window win;
struct v4l2_vbi_format vbi;
struct v4l2_sliced_vbi_format sliced;
struct v4l2_sdr_format sdr;
__u8 raw_data[200];
} 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;
__u32 bytesperline;
__u32 sizeimage;
__u32 colorspace;
__u32 priv;
__u32 flags;
__u32 ycbcr_enc;
__u32 quantization;
__u32 xfer_func;
};
說明:存儲圖像資訊格式的結構體;field為v4l2_field枚舉類型,決定視訊掃描圖像的順序,是逐行還是隔行或是其它,具體用處不清楚,使用者設定時可能無效;bytesperline文檔相鄰行最左邊像素的距離,但是實際是指每行的位元組數;sizeimage圖像大小,計算方式為bytesperline*height;colorspace由驅動設定,如V4L2_COLORSPACE_JPEG(7);
*************************************************************************************************************************************************
struct v4l2_cropcap {
__u32 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;
struct v4l2_rect c;
};
說明:該結構體用來擷取或設定圖像裁剪矩形區域的值。有些裝置不支援裁剪設定,可以通過if(ret == -1 && errno != EINVAL) perror("VIDIOC_S_CROP");來進行判斷裝置該能力。
*************************************************************************************************************************************************
struct v4l2_queryctrl {
__u32 id;
__u32 type;
__u8 name[32];
__s32 minimum;
__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,
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;
__u32 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;
__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;
union {
struct v4l2_captureparm capture;
struct v4l2_outputparm output;
__u8 raw_data[200];
} parm;
};
struct v4l2_captureparm {
__u32 capability;
__u32 capturemode;
struct v4l2_fract timeperframe;
__u32 extendedmode;
__u32 readbuffers;
__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下載下傳(如何不要下載下傳積分?)
源碼學習版連結:https://github.com/ZXX521/V4L2-Qt5.6.0-Ubuntu16.04