基於Streaming I O的V4L2裝置使用

2021-07-30 10:40:30 字數 2902 閱讀 6343

基於v4l2的應用,通常面臨著大塊資料的讀取與拷貝等問題。尤其在嵌入式系統中,對於實時效能要求較高的應用,拷貝會花上幾十個ms的時間,這通常輕則造成使用者體驗差,重則導致產品質量不達標。v4l2 framework定義了幾種不同的方式,用於從裝置中讀取資料,這篇文章簡要介紹下在streaming i/o模式下,如何使用這幾種資料的獲取與使用方法。streaming i/o設計的目的就是為了減少在資料處理的各個環節中,拷貝的次數,從而實現各階段硬體的無縫配合。

本文針對的是usb camera (capture)裝置。

對於裝置特性來說,需要裝置支援streaming能力,這個需要通過v4l2的capability來判斷,方式如下:

struct v4l2_capability _cap;

ioctl( _fd, vidioc_querycap, &_cap );

其中,_fd是開啟的v4l2裝置的描述符,通過:

if( (_cap.capabilities & v4l2_cap_streaming) != 0 )
判斷是否支援streaming方式訪問。

通過memory map訪問v4l2裝置驅動中分配的記憶體。裝置收到的資料存在驅動內的buffer中,通過map方式,將記憶體map到使用者空間。使用這種方式只有指向這段記憶體的使用者空間指標在各個處理環節中傳遞,不會發生真實的資料拷貝。

struct v4l2_requestbuffers reqbuf;

struct *buffers;

unsigned

int i;

memset(&reqbuf, 0, sizeof(reqbuf));

reqbuf.type = v4l2_buf_type_video_capture;

reqbuf.memory = v4l2_memory_mmap;

reqbuf.count = 20;

if (-1 == ioctl (fd, vidioc_reqbufs, &reqbuf))

/* we want at least five buffers. */

if (reqbuf.count < 5)

buffers = calloc(reqbuf.count, sizeof(*buffers));

assert(buffers != null);

for (i = 0; i < reqbuf.count; i++)

buffers[i].length = buffer.length; /* remember for munmap() */

buffers[i].start = mmap(null, buffer.length,

prot_read | prot_write, /* recommended */

map_shared, /* recommended */

fd, buffer.m.offset);

if (map_failed == buffers[i].start)

}/* cleanup. */

for (i = 0; i < reqbuf.count; i++)

munmap(buffers[i].start, buffers[i].length);

使用者程式首先需要通過vidioc_reqbufs,通知驅動進行驅動內記憶體分配;之後通過vidioc_querybuf取得驅動中各記憶體塊的基本資訊,主要是buffer長度和offset;取得這些資訊後,通過mmap,將記憶體map到user space中使用。在驅動中,v4l2對於buffer的使用是佇列形式,buffer出隊後,再次入隊之前,驅動無法再使用這個buffer,因此申請的buffer個數通常是多個,避免資料丟失。

在使用過程中,需要通過poll操作,判斷是否有資料到達,然後通過vidioc_dqbuf,取得當前有資料的buffer,通過buffer的index屬性,找到對應的user space指標,交由下個環節處理;處理完成後,通過vidioc_qbuf,將buffer重新入隊。

user pointers方式會將使用者空間分配的記憶體指標及長度傳遞給v4l2驅動(雖然是使用者空間分配,但不一定是在堆空間上分配的記憶體,可以是通過其它方式對映出來的記憶體,比如從另乙個裝置驅動中),這樣資料到達後,可以直接傳遞這個指標到下個環節中處理。初始化方式如下:

struct v4l2_requestbuffers reqbuf;

memset (&reqbuf, 0, sizeof (reqbuf));

reqbuf.type = v4l2_buf_type_video_capture;

reqbuf.memory = v4l2_memory_userptr;

if (ioctl (fd, vidioc_reqbufs, &reqbuf) == -1)

dma方式的初始化方式如下:

struct v4l2_requestbuffers reqbuf;

memset(&reqbuf, 0, sizeof (reqbuf));

reqbuf.type = v4l2_buf_type_video_capture;

reqbuf.memory = v4l2_memory_dmabuf;

reqbuf.count = 1;

if (ioctl(fd, vidioc_reqbufs, &reqbuf) == -1)

dma方式的傳輸基於檔案描述符進行,fd的傳遞是通過vidioc_qbuf中的描述符設定:

int buffer_queue(int v4lfd, int

index, int dmafd)

return

0;}

poll操作返回後,可以通過這個dmafd進行下一步處理。

v4l2驅動文件之 streaming IO

v4l2驅動編寫篇第六b 流輸入輸出 使用read 和write 方法,每一幀都要通過i o操作在使用者和核心空間之間拷貝資料。然而,當使用流輸入輸出的方式時,這種情況就不會發生。替代的方案是使用者與核心空間之間交換緩衝區的指標,這些緩衝區將被對映到應用的位址空間,這也就使零幀複製數成為可能。有兩種...

基於matlab的音訊波形實時採集顯示 v0 1

robj audiorecorder 44100,16,1 設定取樣頻率 取樣位數 通道數 recordblocking robj,1 採集初步資料 1s長度 rdata getaudiodata robj 獲取音訊資料 plot rdata 繪製波形 axis 1,44100,0.1,0.1 設定...

基於maplefetion的飛信客戶端v1 0

基於maplefetion的飛信客戶端,使用的solosky.xu大牛開發的maplefetion專案裡的api maplefetion 2.5.1 沒什麼技術含量,只是想通過做這個程式鞏固以前的知識,然後再從中學習點其他的知識.由於本人笨,然後還有很多東西不會,半個月就做了這麼點的功能,實在是有點...