天天看點

V4L2+Qt5實作攝像頭視訊采集以及參數控制

這一段時間在做攝像頭控制方面的工作,需要在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下載下傳(如何不要下載下傳積分?)

V4L2+Qt5實作攝像頭視訊采集以及參數控制
V4L2+Qt5實作攝像頭視訊采集以及參數控制
V4L2+Qt5實作攝像頭視訊采集以及參數控制

源碼學習版連結:https://github.com/ZXX521/V4L2-Qt5.6.0-Ubuntu16.04

繼續閱讀