衡阳派盒市场营销有限公司

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

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

3天內不再提示

深入學習Linux攝像頭v4l2應用編程

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

一、什么是v4l2

vl42是video for Linux 2的縮寫,是一套Linux內核視頻設備的驅動框架,該驅動框架為應用層提供一套統一的操作接口(一系列的ioctl)

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

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

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

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

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

二、v4l2 API介紹

對V4L2設備進行編程包括以下步驟

打開設備

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

設置數據格式

設置輸入/輸出方法

輸入/輸出緩存隊列循環

關閉設備

其中大多數操作都是通過應用層調用ioctl實現的,可以將這些ioctl分為下面幾類

2.1 查詢設備的功能

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

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

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

2.2 應用優先級

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

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

2.3 輸入和輸出設備

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

2.4 視頻標準

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

2.5 控制屬性

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

2.6 圖像格式

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

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

2.7 圖像裁剪、插入與縮放

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

2.8 數據的輸入和輸出

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

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

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

三、v4l2設備操作流程

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

step1:打開設備 在Linux中,視頻設備節點為/dev/videox,使用open函數將其打開

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

step 2:查詢設備功能

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設備的功能,capabilities有以下部分標記位:

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

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

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

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

下面介紹如何設置輸入設備

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

structv4l2_inputinput;

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

2.設置輸入設備

structv4l2_inputinput;
input.index=index;//指定輸入設備

if(ioctl(fd,VIDIOC_S_INPUT,&input)

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

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.設置像素格式

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:設置緩存 v4l2設備讀取數據的方式有兩種,一種是read方式,一種是streaming方式,具體需要看step 2的返回結果是支持V4L2_CAP_READWRITE還是V4L2_CAP_STREAMING

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

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

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

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

1.申請緩存

structv4l2_requestbuffersreq;

req.count=nr_bufs;//緩存數量
req.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory=V4L2_MEMORY_MMAP;

if(ioctl(fd,VIDIOC_REQBUFS,&req)

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

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

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

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:打開設備

enumv4l2_buf_typetype=V4L2_BUF_TYPE_VIDEO_CAPTURE;

if(ioctl(fd,VIDIOC_STREAMON,&type)

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

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,然后找到對飲的緩存,通過映射過后的地址進行數據的讀取

3.入隊列 再數據讀取完成后,要將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)

讀取數據就是在上面這三步一直不斷地循環

step 8:關閉設備

1.關閉設備

enumv4l2_buf_typetype=V4L2_BUF_TYPE_VIDEO_CAPTURE;

if(ioctl(fd,VIDIOC_STREAMOFF,&type)

2.取消映射

for(i=0;ilength);

關閉文件描述符

close(fd);

libv4l2 v4l2設備操作起來還是比較繁瑣的,為此我對其進行了封裝,寫了一套庫,使用起來更加方便,可以從這里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.轉換圖像格式,將yuv格式轉換成frame buff可以接收的rgb格式

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

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

執行make編譯后可以得到video2lcd,執行video2lcd /dev/video0

運行效果如下:

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

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

審核編輯:湯梓紅

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

    關注

    3

    文章

    1382

    瀏覽量

    40430
  • 接口
    +關注

    關注

    33

    文章

    8694

    瀏覽量

    151929
  • Linux
    +關注

    關注

    87

    文章

    11345

    瀏覽量

    210417
  • 攝像頭
    +關注

    關注

    60

    文章

    4865

    瀏覽量

    96322

原文標題:深入學習Linux攝像頭v4l2應用編程

文章出處:【微信號:嵌入式應用研究院,微信公眾號:嵌入式應用研究院】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Linux攝像頭應用編程

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

    百問網全志系列開發板攝像頭V4L2編程步驟詳解

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

    v4l2編程經典_

    v4l2編程經典_
    發表于 11-05 12:41

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

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

    【WRTnode2R試用體驗】使用V4L2獲取攝像頭的信息

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

    運行linuxtv官網的v4l2代碼,capture攝像頭時select超時怎么解決?

    編譯,運行linuxtv官網的v4l2代碼,capture 攝像頭時select超時,這怎么搞?
    發表于 12-31 06:12

    運行linuxtv官網的v4l2代碼,capture攝像頭時select超時怎么解決?

    [td]編譯,運行linuxtv官網的v4l2代碼,capture 攝像頭時select超時,這怎么搞?
    發表于 01-14 07:02

    什么是V4L2?有何作用

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

    需要了解Linux V4L2的驅動架構

    video4linux2(V4L2)是Linux內核中關于視頻設備的中間驅動層,向上為Linux應用程序訪問視頻設備提供了通用接口,向下為linux
    發表于 04-28 17:29 ?1171次閱讀
    需要了解<b class='flag-5'>Linux</b> <b class='flag-5'>V4L2</b>的驅動架構

    Linux視頻設備驅動編程(v4l2編程)

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

    Linux應用開發【第七章】攝像頭V4L2編程應用開發

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

    V4L2學習筆記

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

    如何使用v4l2 API讀取攝像頭

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

    Linux開發_攝像頭編程(實現拍照功能)

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

    v4l2編程

    v4l2編程
    發表于 10-28 11:10 ?0次下載
    百家乐免费试玩| 百家乐官网体育直播| 至尊百家乐官网娱乐网| 百家乐官网怎么玩最保险| 百家乐网投打法| A8娱乐城| A8百家乐现金网| 八大胜备用网址| 百家乐免费路单| 郑州市太阳城宾馆| 大余县| 博狗百家乐开户| 澳门赌博| 百家乐玩法开户彩公司| 娱乐城开户免存送现金| 汤阴县| 玩百家乐如何看路| 百家乐博娱乐场开户注册| 百家乐官网辅助分析软件| 百家乐游戏真人游戏| 利博国际网址| 百家乐官网正负计算| 易发国际| 百家乐官网游戏补牌规则| 什么事百家乐的路单| 千亿国际| 百家乐只打一种牌型| 百家乐官网新台第二局| 百家乐桌手机套| 游戏机百家乐官网的技术| 功夫百家乐的玩法技巧和规则 | 百家乐桌颜色可定制| 百家乐官网高手长胜攻略| 百家乐最好投注法是怎样的去哪儿能了解一下啊 | 百家乐六手变化混合赢家打| 百家乐官网游戏网上投注| bet365取消提款| 赌场百家乐试玩| 百家乐官网专用台布| 开花财国际| 机器百家乐心得|