V4L2視頻采集操作流程和接口說明


背景:

  V4L2是V4L的升級版本,為linux下視頻設備程序提供了一套接口規范。包括一套數據結構和底層V4L2驅動接口。

 《WAV文件格式分析

一般操作流程(視頻設備):

1.打開設備文件。

int fd=open("/dev/video0",O_RDWR);

2. 取得設備的capability,看看設備具有什么功能,比如是否具有視頻輸入,或者音頻輸入輸出等。

VIDIOC_QUERYCAP,struct v4l2_capability(可選)

3. 選擇視頻輸入,一個視頻設備可以有多個視頻輸入。

VIDIOC_S_INPUT,struct v4l2_input

4. 設置視頻的制式和幀格式,制式包括PAL,NTSC,幀的格式個包括寬度和高度等。

VIDIOC_S_STD,VIDIOC_S_FMT,struct v4l2_std_id,struct v4l2_format

5. 向驅動申請幀緩沖,一般不超過5個。

struct v4l2_requestbuffers

6. 將申請到的幀緩沖映射到用戶空間,這樣就可以直接操作采集到的幀了,而不必去復制。
7. 將申請到的幀緩沖全部入隊列,以便存放采集到的數據.

VIDIOC_QBUF,struct v4l2_buffer

8. 開始視頻的采集。

VIDIOC_STREAMON

9. 出隊列以取得已采集數據的幀緩沖,取得原始采集數據。

VIDIOC_DQBUF

10. 將緩沖重新入隊列尾,這樣可以循環采集。

VIDIOC_QBUF

11. 停止視頻的采集。

VIDIOC_STREAMOFF

12. 關閉視頻設備。

close(fd);

 

 

V4L2 API及數據結構

 

1、常用的結構體在內核目錄include/linux/videodev2.h中定義

struct v4l2_requestbuffers reqbufs;//向驅動申請幀緩沖的請求,里面包含申請的個數
struct v4l2_capability cap;//這個設備的功能,比如是否是視頻輸入設備
struct v4l2_input input; //視頻輸入
struct v4l2_standard std;//視頻的制式,比如PAL,NTSC
struct v4l2_format fmt;//幀的格式,比如寬度,高度等

struct v4l2_buffer buf;//代表驅動中的一幀
v4l2_std_id stdid;//視頻制式,例如:V4L2_STD_PAL_B
struct v4l2_queryctrl query;//某一類型的控制
struct v4l2_control control;//具體控制的值

 

2、常用的IOCTL接口命令也在include/linux/videodev2.h中定義

VIDIOC_REQBUFS //分配內存 
VIDIOC_QUERYBUF //把VIDIOC_REQBUFS中分配的數據緩存轉換成物理地址
VIDIOC_QUERYCAP //查詢驅動功能
VIDIOC_ENUM_FMT //獲取當前驅動支持的視頻格式
VIDIOC_S_FMT //設置當前驅動的頻捕獲格式
VIDIOC_G_FMT //讀取當前驅動的頻捕獲格式
VIDIOC_TRY_FMT //驗證當前驅動的顯示格式
VIDIOC_CROPCAP //查詢驅動的修剪能力
VIDIOC_S_CROP //設置視頻信號的矩形邊框
VIDIOC_G_CROP //讀取視頻信號的矩形邊框
VIDIOC_QBUF //把數據從緩存中讀取出來
VIDIOC_DQBUF //把數據放回緩存隊列
VIDIOC_STREAMON //開始視頻顯示函數
VIDIOC_STREAMOFF //結束視頻顯示函數
VIDIOC_QUERYSTD //檢查當前視頻設備支持的標准,例如PAL或NTSC。

 

3、操作流程

V4L2提供了很多訪問接口,你可以根據具體需要選擇操作方法。需要注意的是,很少有驅動完全實現了所有的接口功能。所以在使用時需要參考驅動源碼,或仔細閱讀驅動提供者的使用說明。

下面列舉出一種操作的流程,供參考。

 

(1)打開設備文件

int fd = open(Devicename,mode);

    Devicename:/dev/video0、/dev/video1 ……

     Mode:O_RDWR [| O_NONBLOCK]

       如果使用非阻塞模式調用視頻設備,則當沒有可用的視頻數據時,不會阻塞,而立刻返回。

 

(2)選擇視頻輸入

struct v4l2_input input;

input.index = 0;

int ret = ioctl(fd, VIDIOC_S_INPUT, &input);     

一個視頻設備可以有多個視頻輸入。如果只有一路輸入,這個功能可以沒有。

 

(3)設置視頻捕獲格式

struct v4l2_format fmt;

fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32;

fmt.fmt.pix.height = height;

fmt.fmt.pix.width = width;

ret = ioctl(fd, VIDIOC_S_FMT, &fmt);

if(ret) {

  perror("VIDIOC_S_FMT/n");

  close(fd);

  return -1;

}

 

(4)向驅動申請幀緩存

struct v4l2_requestbuffers  req;

if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1) {
    return -1;
}

v4l2_requestbuffers結構中定義了緩存的數量,驅動會據此申請對應數量的視頻緩存。多個緩存可以用於建立FIFO,來提高視頻采集的效率。

 

( 5 )獲取每個緩存的信息,並mmap到用戶空間

typedef struct VideoBuffer {

    void   *start;

    size_t  length;

} VideoBuffer;

                                                              

VideoBuffer*       buffers = calloc( req.count, sizeof(*buffers) );

struct v4l2_buffer    buf;

 

for (numBufs = 0; numBufs < req.count; numBufs++) {//映射所有的緩存

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

    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    buf.memory = V4L2_MEMORY_MMAP;

    buf.index = numBufs;

    if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) {//獲取到對應index的緩存信息,此處主要利用length信息及offset信息來完成后面的mmap操作。

        return -1;

    }

 

    buffers[numBufs].length = buf.length;

    // 轉換成相對地址

    buffers[numBufs].start = mmap(NULL, buf.length,

        PROT_READ | PROT_WRITE,

        MAP_SHARED,

        fd, buf.m.offset);

 

    if (buffers[numBufs].start == MAP_FAILED) {

        return -1;

    }

 

 

 

(6)開始采集視頻

int buf_type= V4L2_BUF_TYPE_VIDEO_CAPTURE;

int ret = ioctl(fd, VIDIOC_STREAMON, &buf_type);

(7)取出FIFO緩存中已經采樣的幀緩存

struct v4l2_buffer buf;

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

buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory=V4L2_MEMORY_MMAP;

buf.index=0;//此值由下面的ioctl返回

if (ioctl(fd, VIDIOC_DQBUF, &buf) == -1)
{
    return -1;
}

根據返回的buf.index找到對應的mmap映射好的緩存,取出視頻數據。

 

(8)將剛剛處理完的緩沖重新入隊列尾,這樣可以循環采集

if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) {

    return -1;

}

 

(9)停止視頻的采集

int ret = ioctl(fd, VIDIOC_STREAMOFF, &buf_type);

 

(10)關閉視頻設備

close(fd);


免責聲明!

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



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