【Qt开发】V4L2 API详解 Buffer的准备和数据读取
生活随笔
收集整理的這篇文章主要介紹了
【Qt开发】V4L2 API详解 Buffer的准备和数据读取
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
前面主要介紹的是:V4L2 的一些設(shè)置接口,如亮度,飽和度,曝光時(shí)間,幀數(shù),增益,白平衡等。今天看看V4L2 得到數(shù)據(jù)的幾個(gè)關(guān)鍵ioctl,Buffer的申請(qǐng)和數(shù)據(jù)的抓取。
1. 初始化 Memory Mapping 或 User Pointer I/O. 申請(qǐng)數(shù)據(jù)Buffer。 int ioctl(int fd, int?requestbuf,?struct v4l2_requestbuffers * argp); 參數(shù)一:open()所產(chǎn)生的句柄。 參數(shù)二:VIDIOC_REQBUFS 參數(shù)三:in/out結(jié)構(gòu)體。 struct v4l2_requestbuffers { __u32 count; enum v4l2_buf_type type; enum v4l2_memory memory; //Applications set this field to?V4L2_MEMORY_MMAP?or?V4L2_MEMORY_USERPTR ?__u32 reserved[2]; };
注意,有兩種方式的I/O。 Memory Mapping 和User Pointer。 Memory Mapping的Buffer由Driver申請(qǐng)為物理連續(xù)的內(nèi)存空間(Kernel空間)。在此ioctl調(diào)用時(shí)被分配,需要早于mmap()動(dòng)作將他們映射到用戶(hù)空間。
1.1:Memory Mapping模式詳解: 在使用Memory Mapping模式時(shí),參數(shù)三中結(jié)構(gòu)體內(nèi)每個(gè)field都需要設(shè)置。
__u32 count; ??//當(dāng)memory=V4L2_MEMORY_MMAP時(shí),此處才有效。表明要申請(qǐng)的buffer個(gè)數(shù)。 enum v4l2_buf_type type; ?//Stream 或者Buffer的類(lèi)型。此處肯定為V4L2_BUF_TYPE_VIDEO_CAPTURE enum v4l2_memory memory; ?//既然是Memory Mapping模式,則此處設(shè)置為:V4L2_MEMORY_MMAP
注意:count是個(gè)輸入輸出函數(shù)。因?yàn)槟闼暾?qǐng)到的Buffer個(gè)數(shù)不一定就是你所輸入的Number。所以在ioctl執(zhí)行后,driver會(huì)將真實(shí)申請(qǐng)到的buffer個(gè)數(shù)填充到此field. 這個(gè)數(shù)目有可能大于你想要申請(qǐng)的,也可能小與,甚至可能是0個(gè)。 應(yīng)用程序可以再次調(diào)用ioctl--VIDIOC_REQBUFS 來(lái)修改buffer個(gè)數(shù)。但前提是必須先釋放已經(jīng)?mapped?的?buffer?,可以先?munmap?,然后設(shè)置參數(shù)?count?為?0?來(lái)釋放所有的?buffer。
支持Memory ?Mapping ?I/O方式的前提是:v4l2_capability??中支持V4L2_CAP_STREAMING。 在這個(gè)模式下,數(shù)據(jù)本身不會(huì)被Copy,只是在Kernel和用戶(hù)態(tài)之間交換。在應(yīng)用程序想要訪(fǎng)問(wèn)到這些數(shù)據(jù)之前,它必須調(diào)用mmap()影射到用戶(hù)態(tài)。
同時(shí)也要注意,通過(guò)ioctl申請(qǐng)的內(nèi)存,是物理內(nèi)存,無(wú)法被交換入Disk,所以一定要釋放:munmap()。
1.2:User Pointer模式: User Pointer模式時(shí),應(yīng)用程序?qū)崿F(xiàn)申請(qǐng)。 只需要填充Type=V4L2_BUF_TYPE_VIDEO_CAPTURE, memory=V4L2_MEMORY_USERPTR
2. 詢(xún)問(wèn)Buffer狀態(tài): int ioctl(int fd, int request, struct?v4l2_buffer* argp); 參數(shù)一:open()所產(chǎn)生的句柄。 參數(shù)二:VIDIOC_QUERYBUF 參數(shù)三:v4l2_buffer 結(jié)構(gòu)體。(IN/OUT參數(shù))
注意,此ioctl是Memory Mapping的I/O方法之一。User Pointer模式不需要。在Buffer在ioctl-VIDIOC_REQBUFS執(zhí)行時(shí)創(chuàng)建后,隨時(shí)都可以調(diào)用此Ioctl得到buffer信息。 視頻緩沖區(qū)的使用狀態(tài)、在內(nèi)核空間的偏移地址、緩沖區(qū)長(zhǎng)度等。在應(yīng)用程序設(shè)計(jì)中通過(guò)調(diào)VIDIOC_QUERYBUF來(lái)獲取內(nèi)核空間的視頻緩沖區(qū)信息,然后調(diào)用函數(shù)mmap把內(nèi)核空間地址映射到用戶(hù)空間,這樣應(yīng)用程序才能夠訪(fǎng)問(wèn)位于內(nèi)核空間的視頻緩沖區(qū)
我們首先通過(guò)v4l2_buffer結(jié)構(gòu)體看看參數(shù)三這個(gè)輸入輸出參數(shù)需要輸入些什么,以及能夠得到什么信息。
struct v4l2_buffer { __u32 index; enum v4l2_buf_type type; __u32 bytesused; __u32 flags; enum v4l2_field field; struct timeval timestamp; struct v4l2_timecode timecode; __u32 sequence;
enum v4l2_memory memory; union { __u32 offset; unsigned long userptr; } m; __u32 length; __u32 input; __u32 reserved; };
在調(diào)用ioctl--VIDIOC_QUERYBUF時(shí),需要寫(xiě)入的項(xiàng)目有: enum v4l2_buf_type type; //V4L2_BUF_TYPE_VIDEO_CAPTURE __u32 index; ?// 這里需要解釋一下,因?yàn)樵谡{(diào)用ioctl-VIDIOC_REQBUFS時(shí),建立了count個(gè)Buffer。所以,這里index的有效范圍是:0到count-1.
在調(diào)用ioctl-VIDIOC_QUERYBUF后,Driver會(huì)填充v4l2_buffer 結(jié)構(gòu)體內(nèi)所有信息供用戶(hù)使用。 如果一些正常: 1. flags 中:V4L2_BUF_FLAG_MAPPED,?V4L2_BUF_FLAG_QUEUED?and?V4L2_BUF_FLAG_DONE被設(shè)置。 2. memory中,V4L2_MEMORY_MMAP被設(shè)置。 3.?m.offset中,從將要mapping 的device memory頭到數(shù)據(jù)頭的offset. 4.?length?中,填充當(dāng)前Buffer長(zhǎng)度。 5。其它的Field有可能設(shè)置,也有可能不被設(shè)置。
這樣,mmap()想要有的信息就全了。而mmap()之后,Device Driver 申請(qǐng)的或者Device Memory就能映射到用戶(hù)空間。數(shù)據(jù)就可以被應(yīng)用程序使用了。這才是ioctl-VIDIOC_QUERYBUF的關(guān)鍵作用。
3.和Driver交換buffer:? 對(duì)Camera這樣的捕獲設(shè)備來(lái)說(shuō),Device將數(shù)據(jù)放到Buffer中,用戶(hù)得到數(shù)據(jù)。Device再次將數(shù)據(jù)放到Buffer中。 那么Device Driver 怎樣知道哪個(gè)Buffer是可以存放數(shù)據(jù)的呢?這就用到當(dāng)前這兩個(gè)ioctl-VIDIOC_QBUF, ioctl-VIDIOC_DQBUF.
ioctl-VIDIOC_QBUF: 將指定的Buffer放到輸入隊(duì)列中,即向Device表明這個(gè)Buffer可以存放東西。 ioctl-VIDIOC_DQBUF: 將輸出隊(duì)列中的數(shù)據(jù) buffer取出。
在?driver?內(nèi)部管理著兩個(gè)?buffer queues?,一個(gè)輸入隊(duì)列,一個(gè)輸出隊(duì)列。對(duì)于?capture device?來(lái)說(shuō),當(dāng)輸入隊(duì)列中的?buffer?被塞滿(mǎn)數(shù)據(jù)以后會(huì)自動(dòng)變?yōu)檩敵鲫?duì)列,等待調(diào)用?VIDIOC_DQBUF?將數(shù)據(jù)進(jìn)行處理以后重新調(diào)用?VIDIOC_QBUF?將?buffer?重新放進(jìn)輸入隊(duì)列.
用法: ioctl--VIDIOC_QBUF: int ioctl(int fd, int request, struct?v4l2_buffer* argp); 參數(shù)一:open()所產(chǎn)生的句柄。 參數(shù)二:VIDIOC_QBUF 參數(shù)三:v4l2_buffer 結(jié)構(gòu)體。(IN/OUT參數(shù))
參數(shù)三是IN/OUT 參數(shù)。需要填充 enum v4l2_buf_type type; //V4L2_BUF_TYPE_VIDEO_CAPTURE __u32 index; ?// 這里需要解釋一下,因?yàn)樵谡{(diào)用ioctl-VIDIOC_REQBUFS時(shí),建立了count個(gè)Buffer。所以,這里index的有效范圍是:0到count-1.? memory:?V4L2_MEMORY_MMAP.
則這個(gè)結(jié)構(gòu)體指明的buffer被送入輸出隊(duì)列,表明此Buffer可以被device 填充數(shù)據(jù)。
用法: ioctl--VIDIOC_DQBUF: int ioctl(int fd, int request, struct?v4l2_buffer* argp); 參數(shù)一:open()所產(chǎn)生的句柄。 參數(shù)二:VIDIOC_DQBUF 參數(shù)三:v4l2_buffer 結(jié)構(gòu)體。(IN/OUT參數(shù))
從輸出隊(duì)列中取出一個(gè)有數(shù)據(jù)的Buffer。這個(gè)Buffer中的數(shù)據(jù)被處理后,此Buffer可以通過(guò)ioctl-VIDIOC_QBUF再次放入輸入隊(duì)列中去。
4. 開(kāi)始和結(jié)束捕獲: ioctl--VIDIOC_STREAMON. ioctl--VIDIOC_STREAMOFF
非常簡(jiǎn)單的調(diào)用。就是開(kāi)始和結(jié)束。
1. 初始化 Memory Mapping 或 User Pointer I/O. 申請(qǐng)數(shù)據(jù)Buffer。 int ioctl(int fd, int?requestbuf,?struct v4l2_requestbuffers * argp); 參數(shù)一:open()所產(chǎn)生的句柄。 參數(shù)二:VIDIOC_REQBUFS 參數(shù)三:in/out結(jié)構(gòu)體。 struct v4l2_requestbuffers { __u32 count; enum v4l2_buf_type type; enum v4l2_memory memory; //Applications set this field to?V4L2_MEMORY_MMAP?or?V4L2_MEMORY_USERPTR ?__u32 reserved[2]; };
注意,有兩種方式的I/O。 Memory Mapping 和User Pointer。 Memory Mapping的Buffer由Driver申請(qǐng)為物理連續(xù)的內(nèi)存空間(Kernel空間)。在此ioctl調(diào)用時(shí)被分配,需要早于mmap()動(dòng)作將他們映射到用戶(hù)空間。
1.1:Memory Mapping模式詳解: 在使用Memory Mapping模式時(shí),參數(shù)三中結(jié)構(gòu)體內(nèi)每個(gè)field都需要設(shè)置。
__u32 count; ??//當(dāng)memory=V4L2_MEMORY_MMAP時(shí),此處才有效。表明要申請(qǐng)的buffer個(gè)數(shù)。 enum v4l2_buf_type type; ?//Stream 或者Buffer的類(lèi)型。此處肯定為V4L2_BUF_TYPE_VIDEO_CAPTURE enum v4l2_memory memory; ?//既然是Memory Mapping模式,則此處設(shè)置為:V4L2_MEMORY_MMAP
注意:count是個(gè)輸入輸出函數(shù)。因?yàn)槟闼暾?qǐng)到的Buffer個(gè)數(shù)不一定就是你所輸入的Number。所以在ioctl執(zhí)行后,driver會(huì)將真實(shí)申請(qǐng)到的buffer個(gè)數(shù)填充到此field. 這個(gè)數(shù)目有可能大于你想要申請(qǐng)的,也可能小與,甚至可能是0個(gè)。 應(yīng)用程序可以再次調(diào)用ioctl--VIDIOC_REQBUFS 來(lái)修改buffer個(gè)數(shù)。但前提是必須先釋放已經(jīng)?mapped?的?buffer?,可以先?munmap?,然后設(shè)置參數(shù)?count?為?0?來(lái)釋放所有的?buffer。
支持Memory ?Mapping ?I/O方式的前提是:v4l2_capability??中支持V4L2_CAP_STREAMING。 在這個(gè)模式下,數(shù)據(jù)本身不會(huì)被Copy,只是在Kernel和用戶(hù)態(tài)之間交換。在應(yīng)用程序想要訪(fǎng)問(wèn)到這些數(shù)據(jù)之前,它必須調(diào)用mmap()影射到用戶(hù)態(tài)。
同時(shí)也要注意,通過(guò)ioctl申請(qǐng)的內(nèi)存,是物理內(nèi)存,無(wú)法被交換入Disk,所以一定要釋放:munmap()。
1.2:User Pointer模式: User Pointer模式時(shí),應(yīng)用程序?qū)崿F(xiàn)申請(qǐng)。 只需要填充Type=V4L2_BUF_TYPE_VIDEO_CAPTURE, memory=V4L2_MEMORY_USERPTR
2. 詢(xún)問(wèn)Buffer狀態(tài): int ioctl(int fd, int request, struct?v4l2_buffer* argp); 參數(shù)一:open()所產(chǎn)生的句柄。 參數(shù)二:VIDIOC_QUERYBUF 參數(shù)三:v4l2_buffer 結(jié)構(gòu)體。(IN/OUT參數(shù))
注意,此ioctl是Memory Mapping的I/O方法之一。User Pointer模式不需要。在Buffer在ioctl-VIDIOC_REQBUFS執(zhí)行時(shí)創(chuàng)建后,隨時(shí)都可以調(diào)用此Ioctl得到buffer信息。 視頻緩沖區(qū)的使用狀態(tài)、在內(nèi)核空間的偏移地址、緩沖區(qū)長(zhǎng)度等。在應(yīng)用程序設(shè)計(jì)中通過(guò)調(diào)VIDIOC_QUERYBUF來(lái)獲取內(nèi)核空間的視頻緩沖區(qū)信息,然后調(diào)用函數(shù)mmap把內(nèi)核空間地址映射到用戶(hù)空間,這樣應(yīng)用程序才能夠訪(fǎng)問(wèn)位于內(nèi)核空間的視頻緩沖區(qū)
我們首先通過(guò)v4l2_buffer結(jié)構(gòu)體看看參數(shù)三這個(gè)輸入輸出參數(shù)需要輸入些什么,以及能夠得到什么信息。
struct v4l2_buffer { __u32 index; enum v4l2_buf_type type; __u32 bytesused; __u32 flags; enum v4l2_field field; struct timeval timestamp; struct v4l2_timecode timecode; __u32 sequence;
enum v4l2_memory memory; union { __u32 offset; unsigned long userptr; } m; __u32 length; __u32 input; __u32 reserved; };
在調(diào)用ioctl--VIDIOC_QUERYBUF時(shí),需要寫(xiě)入的項(xiàng)目有: enum v4l2_buf_type type; //V4L2_BUF_TYPE_VIDEO_CAPTURE __u32 index; ?// 這里需要解釋一下,因?yàn)樵谡{(diào)用ioctl-VIDIOC_REQBUFS時(shí),建立了count個(gè)Buffer。所以,這里index的有效范圍是:0到count-1.
在調(diào)用ioctl-VIDIOC_QUERYBUF后,Driver會(huì)填充v4l2_buffer 結(jié)構(gòu)體內(nèi)所有信息供用戶(hù)使用。 如果一些正常: 1. flags 中:V4L2_BUF_FLAG_MAPPED,?V4L2_BUF_FLAG_QUEUED?and?V4L2_BUF_FLAG_DONE被設(shè)置。 2. memory中,V4L2_MEMORY_MMAP被設(shè)置。 3.?m.offset中,從將要mapping 的device memory頭到數(shù)據(jù)頭的offset. 4.?length?中,填充當(dāng)前Buffer長(zhǎng)度。 5。其它的Field有可能設(shè)置,也有可能不被設(shè)置。
這樣,mmap()想要有的信息就全了。而mmap()之后,Device Driver 申請(qǐng)的或者Device Memory就能映射到用戶(hù)空間。數(shù)據(jù)就可以被應(yīng)用程序使用了。這才是ioctl-VIDIOC_QUERYBUF的關(guān)鍵作用。
3.和Driver交換buffer:? 對(duì)Camera這樣的捕獲設(shè)備來(lái)說(shuō),Device將數(shù)據(jù)放到Buffer中,用戶(hù)得到數(shù)據(jù)。Device再次將數(shù)據(jù)放到Buffer中。 那么Device Driver 怎樣知道哪個(gè)Buffer是可以存放數(shù)據(jù)的呢?這就用到當(dāng)前這兩個(gè)ioctl-VIDIOC_QBUF, ioctl-VIDIOC_DQBUF.
ioctl-VIDIOC_QBUF: 將指定的Buffer放到輸入隊(duì)列中,即向Device表明這個(gè)Buffer可以存放東西。 ioctl-VIDIOC_DQBUF: 將輸出隊(duì)列中的數(shù)據(jù) buffer取出。
在?driver?內(nèi)部管理著兩個(gè)?buffer queues?,一個(gè)輸入隊(duì)列,一個(gè)輸出隊(duì)列。對(duì)于?capture device?來(lái)說(shuō),當(dāng)輸入隊(duì)列中的?buffer?被塞滿(mǎn)數(shù)據(jù)以后會(huì)自動(dòng)變?yōu)檩敵鲫?duì)列,等待調(diào)用?VIDIOC_DQBUF?將數(shù)據(jù)進(jìn)行處理以后重新調(diào)用?VIDIOC_QBUF?將?buffer?重新放進(jìn)輸入隊(duì)列.
用法: ioctl--VIDIOC_QBUF: int ioctl(int fd, int request, struct?v4l2_buffer* argp); 參數(shù)一:open()所產(chǎn)生的句柄。 參數(shù)二:VIDIOC_QBUF 參數(shù)三:v4l2_buffer 結(jié)構(gòu)體。(IN/OUT參數(shù))
參數(shù)三是IN/OUT 參數(shù)。需要填充 enum v4l2_buf_type type; //V4L2_BUF_TYPE_VIDEO_CAPTURE __u32 index; ?// 這里需要解釋一下,因?yàn)樵谡{(diào)用ioctl-VIDIOC_REQBUFS時(shí),建立了count個(gè)Buffer。所以,這里index的有效范圍是:0到count-1.? memory:?V4L2_MEMORY_MMAP.
則這個(gè)結(jié)構(gòu)體指明的buffer被送入輸出隊(duì)列,表明此Buffer可以被device 填充數(shù)據(jù)。
用法: ioctl--VIDIOC_DQBUF: int ioctl(int fd, int request, struct?v4l2_buffer* argp); 參數(shù)一:open()所產(chǎn)生的句柄。 參數(shù)二:VIDIOC_DQBUF 參數(shù)三:v4l2_buffer 結(jié)構(gòu)體。(IN/OUT參數(shù))
從輸出隊(duì)列中取出一個(gè)有數(shù)據(jù)的Buffer。這個(gè)Buffer中的數(shù)據(jù)被處理后,此Buffer可以通過(guò)ioctl-VIDIOC_QBUF再次放入輸入隊(duì)列中去。
4. 開(kāi)始和結(jié)束捕獲: ioctl--VIDIOC_STREAMON. ioctl--VIDIOC_STREAMOFF
非常簡(jiǎn)單的調(diào)用。就是開(kāi)始和結(jié)束。
轉(zhuǎn)載于:https://www.cnblogs.com/huty/p/8518249.html
總結(jié)
以上是生活随笔為你收集整理的【Qt开发】V4L2 API详解 Buffer的准备和数据读取的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 卡还王还款时一直不扣款是为什么?怎么解决
- 下一篇: vs里根据json快速创建对应类的方法