V4L2 API詳解 背景知識

www.linuxtv.org下,有篇文檔詳細講解了V4L2相關知識和體系結構。是V4L2方面最全面的文檔。可以通過它學習V4L2的一些思路和想法。
http://www.linuxtv.org/downloads/v4l-dvb-apis/index.html

文檔包含的內容主要是Linux Kernel對 用戶空間使用者提供的Video和Audio流Device. 包括video Cameras,模擬/數字電視接收器卡,AM/FM接受卡,流捕捉Device。


對V4L2 Device編程,通常包含以下步驟:
1. 打開Device。 
2. 改變devcie的特性,選擇video或者audio 輸入,video 標準,圖像亮度等等。
3. 協商數據格式。
4. 協商輸入/輸入的方法。
5. 真實的輸入/輸出 Loop。
6. 關閉Device。


0.打開和關閉設備:
0.1: 設備名:
V4L2 driver以Kernel Modules形態實現,它在被root用戶手動insmod 或者在設備首次被插入時被載入。driver 模塊將被掛載在videodev模塊下。

每個driver在載入是都會註冊一個或多個主設備號爲81,此設備號爲0-255的device node.  如何分配次設備號,完全取決於root用戶(SamInfo:其實不指定的話,系統也會自動分配沒有被佔用的次設備號)。這個方式的本意是爲了解決device衝突。

模塊的參數可以選擇次設備號,此以設備名爲前綴的的_nr中。例如:video_0表明/dev/video(0+Base). 
其中,video的base爲0。radio的base則爲64。
#insmod mydriver.ko video_nr=0,1 radio_nr=0,1


1. 關聯設備:
Device可以支持幾個相關的功能,例如video Capture,video overlay (注1)和 VBI capturing相關聯,因爲其功能共享。video 輸入設備和tuner也類似。V4L和早期版本的V4L2 對Video Capture 和Video Overlay採用同樣的命名方式和同樣範圍的子設備號,但VBI設備則不同。這種方式有很多問題,更嚴重的是, V4L videodev 禁止多重打開。


2. 設備的多次打開:
通常,V4L2設備可以被打開多次, 當驅動支持這個功能時,用戶可以在其它應用程序捕捉Video或者Audio時,同時打開設備調節亮度或者音量.

多重打開功能是可選的,Driver至少應該支持用戶在沒有數據訪問的情況下併發打開.
因爲可以多重打開,所以理論上就應該可以設置優先級別(VIDIOC_G_PRIORITY和VIDIOC_S_PRIORITY),優先級高的應用程序可以成功修改一些設置,優先級低的設備去修改時,則會報失敗EBUSY。



3. 共享數據流(Shared Data Streams)
V4L2 driver 不支持多個應用程序通過copy buffer讀寫Device的同一個數據流。非要這麼幹,可以使用在用戶空間的代理程序。如果驅動支持流共享,那麼其實現必須是透明的。V4L2 API 並沒有列出產生衝突時要如何來解決。


4. 能力查詢:(Querying Capabilites)
V4L2 包含很寬廣的使用範圍。 所以首先需要查詢其設備能力集。
通常,使用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。


5.格式查選和設置:
這裏的格式,其實是指抓到的每一幀數據的相關格式.例如: 長,寬,像素,field等。
5.1:得到當前格式:
VIDIOC_G_FMT。
ioctl(Handle, VIDIOC_G_FMT, &Format)
參數三:
與很多ioctl類似, 它是個in/out參數。

struct v4l2_format
{
 enum v4l2_buf_type type;
 union
 {
 struct v4l2_pix_format pix;
 struct v4l2_window win;
 struct v4l2_vbi_format vbi;
 struct v4l2_sliced_vbi_format sliced;
 __u8 raw_data[200];
 } fmt;
};

v4l2_buf_type  type; 輸入信息,讓用戶選擇是哪種類型的設備。這裏又與Driver中對應起來了。

struct v4l2_pix_format pix;
struct v4l2_pix_format
{
 __u32 width;   //抓取楨的寬度
 __u32 height;   //楨高度
 __u32 pixelformat;  //像素格式。例如:V4L2_PIX_FMT_YUYV,V4L2_PIX_FMT_RGB332等。
 enum v4l2_field field; //image包含逐行數據還是隔行數據。如果是隔行數據,是奇行還是偶行(下一篇詳細講述)
 __u32 bytesperline; //每行多少字節,通過width,height,pixelformat可以算出
 __u32 sizeimage;    //每楨多少字節。也可以算出。但需要加入field信息才能算出
 enum v4l2_colorspace colorspace;
 __u32 priv;
};

好像首次取 sizeimage,可能會取到不正確的值。

5.2:設置Format:
VIDIOC_S_FMT:
io_rel = ioctl(Handle, VIDIOC_S_FMT, &Format);
在設置之前,需要填寫參數3Format內容.
例如;
Format.fmt.pix.width =  Width;
Format.fmt.pix.height = Height;
Format.fmt.pix.pixelformat= pixelformat;//V4L2_PIX_FMT_YUYV;
Format.fmt.pix.field = V4L2_FIELD_INTERLACED;


6. Streaming 信息得到和設置
前面Format是單幀數據的設置。現在咱們需要設置和流有關的信息。如楨數。
6.1:得到當前Stream信息:
利用ioctl:
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);
與之前類似,關鍵還是在參數三:
struct v4l2_streamparm
{
 enum v4l2_buf_type type;
 union
 {
 struct v4l2_captureparm capture;
 struct v4l2_outputparm output;
 __u8 raw_data[200];
 } parm;
};

type是個in/out參數,咱們是Camera捕捉設備,所以選用V4L2_BUF_TYPE_VIDEO_CAPTURE。

 struct v4l2_captureparm capture;
struct v4l2_captureparm
{
 __u32 capability;  //功能標籤。目前爲止已經定義的只有一個V4L2_CAP_TIMEPERFRAME,它代表可以改變幀頻率
 __u32 capturemode;   //一個標籤的字段:V4L2_MODE_HIGHQUALITY,這個標籤意在使硬件在高清模式下工作,實現單幀的捕獲。這個模式可以做出任何的犧牲(包括支持的格式,曝光時間等),以達到設備可以處理的最佳圖片質量。
 struct v4l2_fract timeperframe;
 __u32 extendedmode;//它在API中沒有明確的意義
 __u32 readbuffers;//read()操作被調用時內核應爲輸入的幀準備的緩衝區數量
 __u32 reserved[4];
};

調節的關鍵在 struct v4l2_fract timeperframe;
struct v4l2_fract {
 __u32 numerator;   //FPS的分子
 __u32 denominator; // FPS的分母
};
例如: numerator=1, denominator= 30. 則表明每秒30幀。



6.2:設置Stream Setting
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);







注1:
Video Capture(視頻捕捉)和Video overlay的區別:
vieo overlay不同於video capture,是指不需要對video信號的幀進行copy,直接將視頻信號轉化成顯卡的VGA信號或者將捕獲到的視頻幀直接存放在顯卡的內存中
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章