RM新时代网站-首页

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

深入學習Linux攝像頭v4l2應(yīng)用編程

嵌入式應(yīng)用研究院 ? 來源: 嵌入式應(yīng)用研究院 ? 2023-11-15 09:28 ? 次閱讀

一、什么是v4l2

vl42是video for Linux 2的縮寫,是一套Linux內(nèi)核視頻設(shè)備的驅(qū)動框架,該驅(qū)動框架為應(yīng)用層提供一套統(tǒng)一的操作接口(一系列的ioctl)

V4L2在設(shè)計時,是要支持很多廣泛的設(shè)備的,它們之中只有一部分在本質(zhì)上是真正的視頻設(shè)備,可以支持多種設(shè)備,它可以有以下幾種接口

video capture interface:視頻采集接口,這種接口應(yīng)用于攝像頭,v4l2在最初設(shè)計的時候就是應(yīng)用于這種功能

video output interface:視頻輸出接口,將靜止圖像或圖像序列編碼為模擬視頻信號,通過此接口,應(yīng)用程序可以控制編碼過程并將圖像從用戶空間移動到驅(qū)動程序

video overlay interface:視頻直接傳輸接口,可以將采集到的視頻數(shù)據(jù)直接傳輸?shù)斤@示設(shè)備,不需要cpu參與,這種方式的顯示圖像的效率比其他方式高得多

其他接口這里就不介紹了,下面來看一下v4l2的API

二、v4l2 API介紹

對V4L2設(shè)備進行編程包括以下步驟

打開設(shè)備

更改設(shè)備屬性,選擇視頻和音頻輸入,視頻標準,圖片亮度等

設(shè)置數(shù)據(jù)格式

設(shè)置輸入/輸出方法

輸入/輸出緩存隊列循環(huán)

關(guān)閉設(shè)備

其中大多數(shù)操作都是通過應(yīng)用層調(diào)用ioctl實現(xiàn)的,可以將這些ioctl分為下面幾類

2.1 查詢設(shè)備的功能

由于V4L2涵蓋了各種各樣的設(shè)備,因此并非API的所有方面都適用于所有類型的設(shè)備,在使用v4l2設(shè)備時,必須調(diào)用此API,獲得設(shè)備支持的功能(capture、output、overlay…)

注:可以點擊名稱查看API講解

bede8272-830e-11ee-939d-92fbcf53809c.png

2.2 應(yīng)用優(yōu)先級

當多個應(yīng)用程序共享設(shè)備時,可能需要為它們分配不同的優(yōu)先級。視頻錄制應(yīng)用程序可以例如阻止其他應(yīng)用程序改變視頻控制或切換當前的電視頻道。另一個目標是允許在后臺工作的低優(yōu)先級應(yīng)用程序,這些應(yīng)用程序可以被用戶控制的應(yīng)用程序搶占,并在以后自動重新獲得對設(shè)備的控制

beed130a-830e-11ee-939d-92fbcf53809c.png

2.3 輸入和輸出設(shè)備

bef6ba0e-830e-11ee-939d-92fbcf53809c.png

2.4 視頻標準

bf009f74-830e-11ee-939d-92fbcf53809c.png

2.5 控制屬性

bf0a7a94-830e-11ee-939d-92fbcf53809c.png

2.6 圖像格式

圖像由多種格式Y(jié)UV和RGB還有壓縮格式等等,其中每種格式又分有多種格式,比如RGB:RGB565、RGB888…所以在使用設(shè)備時,需要對格式進行設(shè)置

bf150964-830e-11ee-939d-92fbcf53809c.png

2.7 圖像裁剪、插入與縮放

bf1f801a-830e-11ee-939d-92fbcf53809c.png

2.8 數(shù)據(jù)的輸入和輸出

內(nèi)核中使用緩存隊列對圖像數(shù)據(jù)進行管理,用戶空間獲取圖像數(shù)據(jù)有兩種方式,一種是通過read、write方式讀取內(nèi)核空間的緩存,一種是將內(nèi)核空間的緩存映射到用戶空間。在操作v4l2設(shè)備時,通過VIDIOC_QUERYCAP獲取設(shè)備支持哪種方式

ioctl API就先介紹到這里,還有非常多的接口這里就不一一介紹了,具體可以查看V4L2 Function Reference;下面來講一講如何使用這些接口

bf29c188-830e-11ee-939d-92fbcf53809c.png

三、v4l2設(shè)備操作流程

V4L2支持多種接口:capture(捕獲)、output(輸出)、overlay(預(yù)覽)等等 這里講解如何使用capture功能,下面講解操作流程

step1:打開設(shè)備 在Linux中,視頻設(shè)備節(jié)點為/dev/videox,使用open函數(shù)將其打開

intfd=open(name,flag);
if(fd

step 2:查詢設(shè)備功能

if(ioctl(fd,VIDIOC_QUERYCAP,cap)

看一看v4l2_capability:

structv4l2_capability{
__u8driver[16];/*i.e."bttv"*/
__u8card[32];/*i.e."HauppaugeWinTV"*/
__u8bus_info[32];/*"PCI:"+pci_name(pci_dev)*/
__u32version;/*shoulduseKERNEL_VERSION()*/
__u32capabilities;/*Devicecapabilities*/
__u32reserved[4];
};

其中最重要的是capabilities字段,這個字段標記著v4l2設(shè)備的功能,capabilities有以下部分標記位:

bf34211e-830e-11ee-939d-92fbcf53809c.png

我們可以通過這樣子去判斷設(shè)備的功能:

step 3:設(shè)置輸入設(shè)備 一個設(shè)備可能有多個輸入,比如:在芯片上,攝像頭控制器和攝像頭接口是分離的,需要選擇哪一個攝像頭接口作為攝像頭控制器的輸入源

當然,并不是所有的設(shè)備都需要設(shè)置輸入,比如:uvc攝像頭,一般只有一個輸入,默認就會選擇,不需要設(shè)置

下面介紹如何設(shè)置輸入設(shè)備

1.枚舉輸入設(shè)備 下面這段程序枚舉了該設(shè)備所有的輸入源,并打印輸入源的名稱:

structv4l2_inputinput;

input.index=0;
while(!ioctl(fd,VIDIOC_ENUMINPUT,&input))
{
printf("input:%s
",input.name);
++input.index;
}

2.設(shè)置輸入設(shè)備

structv4l2_inputinput;
input.index=index;//指定輸入設(shè)備

if(ioctl(fd,VIDIOC_S_INPUT,&input)

step 4:設(shè)置圖像格式 有的攝像頭支持多種像素格式,有的攝像頭只支持一種像素格式,在設(shè)置格式之前,要先枚舉出所有的格式,看一看是否支持要設(shè)置的格式,然后再進一步設(shè)置

1.枚舉支持的像素格式

structv4l2_fmtdescfmtdesc;

fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmtdesc.index=0;

while(!ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc))
{
printf("fmt:%s
",fmtdesc.description);

fmtdesc.index++;
}

2.設(shè)置像素格式

structv4l2_formatv4l2_fmt;

memset(&v4l2_fmt,0,sizeof(structv4l2_format));
v4l2_fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_fmt.fmt.pix.width=width;//寬度
v4l2_fmt.fmt.pix.height=height;//高度
v4l2_fmt.fmt.pix.pixelformat=V4L2_PIX_FMT_YUYV;//像素格式
v4l2_fmt.fmt.pix.field=V4L2_FIELD_ANY;

if(ioctl(fd,VIDIOC_S_FMT,&v4l2_fmt)

step 5:設(shè)置緩存 v4l2設(shè)備讀取數(shù)據(jù)的方式有兩種,一種是read方式,一種是streaming方式,具體需要看step 2的返回結(jié)果是支持V4L2_CAP_READWRITE還是V4L2_CAP_STREAMING

read方式很容易理解,就是通過read函數(shù)讀取,那么streaming是什么意思呢?

streaming就是在內(nèi)核空間中維護一個緩存隊列,然后將內(nèi)存映射到用戶空間,應(yīng)用讀取圖像數(shù)據(jù)就是一個不斷地出隊列和入隊列的過程,如下圖所示:

bf3f4aa8-830e-11ee-939d-92fbcf53809c.png

下面講解如何去申請和映射緩存:

1.申請緩存

structv4l2_requestbuffersreq;

req.count=nr_bufs;//緩存數(shù)量
req.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory=V4L2_MEMORY_MMAP;

if(ioctl(fd,VIDIOC_REQBUFS,&req)

2.映射緩存 為什么要映射緩存?

因為如果使用read方式讀取的話,圖像數(shù)據(jù)是從內(nèi)核空間拷貝會應(yīng)用空間,而一副圖像的數(shù)據(jù)一般來講是比較大的,所以效率會比較低。而如果使用映射的方式,講內(nèi)核空間的內(nèi)存應(yīng)用到用戶空間,那么用戶空間讀取數(shù)據(jù)就想在操作內(nèi)存一樣,不需要經(jīng)過內(nèi)核空間到用戶空間的拷貝,大大提高效率

映射緩存需要先查詢緩存信息,然后再使用緩存信息進行映射,下面是一個例子:

structv4l2_bufferv4l2_buffer;
void*addr;

memset(&v4l2_buffer,0,sizeof(structv4l2_buffer));
v4l2_buffer.index=i;//想要查詢的緩存
v4l2_buffer.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_buffer.memory=V4L2_MEMORY_MMAP;

/*查詢緩存信息*/
ret=ioctl(fd,VIDIOC_QUERYBUF,&v4l2_buffer);
if(ret

注:需要將所有申請的緩存使用上述方法進行映射

3.將所有的緩存放入隊列

structv4l2_bufferv4l2_buffer;

for(i=0;i

step 6:打開設(shè)備

enumv4l2_buf_typetype=V4L2_BUF_TYPE_VIDEO_CAPTURE;

if(ioctl(fd,VIDIOC_STREAMON,&type)

step 7:讀取數(shù)據(jù) 獲取圖像數(shù)據(jù)其實就是一個不斷地入隊列和出隊列地過程,在出隊列前要調(diào)用poll等待數(shù)據(jù)準備完成

1.poll

structpollfdpoll_fds[1];

poll_fds[0].fd=fd;
poll_fds[0].events=POLLIN;//等待可讀

poll(poll_fds,1,10000);

2.出隊列

structv4l2_bufferbuffer;

buffer.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
buffer.memory=V4L2_MEMORY_MMAP;

if(ioctl(fd,VIDIOC_DQBUF,&buffer)

出隊列后得到了緩存的下標buffer.index,然后找到對飲的緩存,通過映射過后的地址進行數(shù)據(jù)的讀取

3.入隊列 再數(shù)據(jù)讀取完成后,要將buf重新放入隊列中:

structv4l2_bufferv4l2_buf;

v4l2_buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_buf.memory=V4L2_MEMORY_MMAP;
v4l2_buf.index=i;//指定buf

if(ioctl(fd,VIDIOC_QBUF,&v4l2_buf)

讀取數(shù)據(jù)就是在上面這三步一直不斷地循環(huán)

step 8:關(guān)閉設(shè)備

1.關(guān)閉設(shè)備

enumv4l2_buf_typetype=V4L2_BUF_TYPE_VIDEO_CAPTURE;

if(ioctl(fd,VIDIOC_STREAMOFF,&type)

2.取消映射

for(i=0;ilength);

關(guān)閉文件描述符

close(fd);

libv4l2 v4l2設(shè)備操作起來還是比較繁瑣的,為此我對其進行了封裝,寫了一套庫,使用起來更加方便,可以從這里libv4l2獲取

其中附帶一個實例example_cature,通過capture /dev/video0運行程序采集一張YUYV格式的圖片,采集后得到了pic.yuv,可以通過ffplay查看ffplay -pixel_format yuyv422 -f rawvideo -video_size 640x480 pic.yuv,效果圖如下

四、v4l2采集圖像在frame buffer顯示

如何將采集圖像在frame buff上顯示?

1.轉(zhuǎn)換圖像格式,將yuv格式轉(zhuǎn)換成frame buff可以接收的rgb格式

2.操作frame buff,通過映射frame buff的顯存到用戶空間,直接寫顯存就可以顯示圖像

具體的實現(xiàn)過程這里就不詳細說了,下面給出一個例子。

執(zhí)行make編譯后可以得到video2lcd,執(zhí)行video2lcd /dev/video0

運行效果如下:

五、v4l2采集圖像使用Qt顯示

如何使用qt顯示,道理跟在frame buff上顯示是一樣的,都是采集,轉(zhuǎn)化格式,顯示,只是在顯示部分不同而已,這里給出一個例子。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 內(nèi)核
    +關(guān)注

    關(guān)注

    3

    文章

    1372

    瀏覽量

    40276
  • 接口
    +關(guān)注

    關(guān)注

    33

    文章

    8575

    瀏覽量

    151015
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11292

    瀏覽量

    209323
  • 攝像頭
    +關(guān)注

    關(guān)注

    59

    文章

    4836

    瀏覽量

    95599

原文標題:深入學習Linux攝像頭v4l2應(yīng)用編程

文章出處:【微信號:嵌入式應(yīng)用研究院,微信公眾號:嵌入式應(yīng)用研究院】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    Linux攝像頭應(yīng)用編程

    V4L2是Video for linux2的簡稱,為linux中關(guān)于視頻設(shè)備的內(nèi)核驅(qū)動。在Linux中,視頻設(shè)備是設(shè)備文件,可以像訪問普通文件一樣對其進行讀寫,
    的頭像 發(fā)表于 08-26 21:39 ?2870次閱讀
    <b class='flag-5'>Linux</b>下<b class='flag-5'>攝像頭</b>應(yīng)用<b class='flag-5'>編程</b>

    百問網(wǎng)全志系列開發(fā)板攝像頭V4L2編程步驟詳解

    7 攝像頭V4L2編程 7.1 V4L2簡介 ?Video for Linux two(Video4Li
    發(fā)表于 08-13 09:45

    v4l2編程經(jīng)典_

    v4l2編程經(jīng)典_
    發(fā)表于 11-05 12:41

    如何在Raspberry Pi(樹莓派)上調(diào)用V4L2來操縱攝像頭拍照

    如何在Raspberry Pi(樹莓派)上調(diào)用V4L2來操縱攝像頭拍照簡單地說,它就是一個基于ARM CPU的、信用卡那么大的迷你計算機。我曾經(jīng)寫過一篇教程,展示了如何調(diào)用OpenCV,來控制攝像頭
    發(fā)表于 06-30 21:39

    【W(wǎng)RTnode2R試用體驗】使用V4L2獲取攝像頭的信息

    V4L2全稱是Video for Linux 2,通過它可以驅(qū)動攝像頭。在Ubuntu中,已經(jīng)內(nèi)置了V4L2,因此不需要安裝多余的東西。在W
    發(fā)表于 10-26 20:36

    運行l(wèi)inuxtv官網(wǎng)的v4l2代碼,capture攝像頭時select超時怎么解決?

    編譯,運行l(wèi)inuxtv官網(wǎng)的v4l2代碼,capture 攝像頭時select超時,這怎么搞?
    發(fā)表于 12-31 06:12

    運行l(wèi)inuxtv官網(wǎng)的v4l2代碼,capture攝像頭時select超時怎么解決?

    [td]編譯,運行l(wèi)inuxtv官網(wǎng)的v4l2代碼,capture 攝像頭時select超時,這怎么搞?
    發(fā)表于 01-14 07:02

    什么是V4L2?有何作用

    1.什么是V4L2Video for(4) Linux 2 的簡稱,V4L的升級版。V4L2
    發(fā)表于 01-17 09:05

    需要了解Linux V4L2的驅(qū)動架構(gòu)

    video4linux2(V4L2)是Linux內(nèi)核中關(guān)于視頻設(shè)備的中間驅(qū)動層,向上為Linux應(yīng)用程序訪問視頻設(shè)備提供了通用接口,向下為linux
    發(fā)表于 04-28 17:29 ?1134次閱讀
    需要了解<b class='flag-5'>Linux</b> <b class='flag-5'>V4L2</b>的驅(qū)動架構(gòu)

    Linux視頻設(shè)備驅(qū)動編程(v4l2編程)

    一.什么是video4linuxVideo4linux2(簡稱V4L2),是linux中關(guān)于視頻設(shè)備的內(nèi)核驅(qū)動。在Linux中,視頻設(shè)備是設(shè)備文件,可以像訪問普通文件一
    發(fā)表于 04-02 14:35 ?902次閱讀

    Linux應(yīng)用開發(fā)【第七章】攝像頭V4L2編程應(yīng)用開發(fā)

    文章目錄 7 攝像頭V4L2編程應(yīng)用開發(fā) 7.1 V4L2簡介 7.2 V4L2視頻采集原理 7.3 V
    的頭像 發(fā)表于 12-10 19:23 ?3088次閱讀
    <b class='flag-5'>Linux</b>應(yīng)用開發(fā)【第七章】<b class='flag-5'>攝像頭</b><b class='flag-5'>V4L2</b><b class='flag-5'>編程</b>應(yīng)用開發(fā)

    V4L2學習筆記

    1.什么是V4L2Video for(4) Linux 2 的簡稱,V4L的升級版。V4L2
    發(fā)表于 01-17 13:43 ?12次下載
    <b class='flag-5'>V4L2</b><b class='flag-5'>學習</b>筆記

    如何使用v4l2 API讀取攝像頭

    V4L2是Video For Linux的第二個版本,它是Linux的視頻捕獲的API。在這里,您可以找到有關(guān)的文檔。它提供了很方便的c,c++和python接口
    發(fā)表于 02-07 11:16 ?4次下載
    如何使用<b class='flag-5'>v4l2</b> API讀取<b class='flag-5'>攝像頭</b>

    Linux開發(fā)_攝像頭編程(實現(xiàn)拍照功能)

    這篇文章主要介紹Linux下UVC免驅(qū)攝像頭操作流程,介紹V4L2框架、完成攝像頭拍照保存為BMP圖像到本地,最后貼出了利用CJSON庫解析天氣預(yù)報、北京時間接口返回的數(shù)據(jù)例子代碼(上
    的頭像 發(fā)表于 09-17 15:34 ?1845次閱讀

    v4l2編程

    v4l2編程
    發(fā)表于 10-28 11:10 ?0次下載
    RM新时代网站-首页