V4L是linux內核中關于視頻設備的子系統,為linux下的視頻驅動提供了統一的接口,使應用程序可以使用統一的API操作不同的視頻設備,簡化視頻系統的開發與維護
V4L2相比與V4L有更好的擴展性和靈活性
(一)V4L2支持設備:
V4L2可以支持多種設備,可以有以下幾種接口:
1)視頻采集接口
2)視頻輸出接口
3)直接傳輸視頻接口:將視頻采集設備上采集的信號直接輸出到視頻輸出設備上,不用經過系統CPU
4)視頻間隔消隱信號接口(VBI Interface):使引用可以訪問傳輸消隱期的視頻信號
5)收音機接口:
?
(二)V4L2設備處理流程
打開V4L2設備節點
int fd = open( " /dev/video0 " ,O_RDWR |O_NONBLOCK);
配置設備/查詢設備屬性
int ioctl ( int fd, unsigned long int request, ... /* args */ ) ;
常見的request命令:
VIDIOC_REQBUFS:在內核空間中分配幀緩沖區
struct v4l2_requestbuffers req; req.count = 4 ; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; ioctl(fd,VIDIOC_REQBUFS, &req);
VIDIOC_QUERYBUF:將REQBUFS中分配的緩存轉換成物理地址,并將物理地址映射到用戶空間
for (n_buffers = 0 ; n_buffers < req.count; ++ n_buffers) { struct v4l2_buffer buf; memset( &buf, 0 , sizeof (buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = n_buffers; if (- 1 == ioctl(fd, VIDIOC_QUERYBUF, & buf)) { printf( " error in VIDIOC_QUERYBUF\n " ); return - 1 ; } buffers[n_buffers].length = buf.length; buffers[n_buffers].start =mmap (NULL,buf.length,PROT_READ | PROT_WRITE ,MAP_SHARED,fd, buf.m.offset); if (MAP_FAILED== buffers[n_buffers].start) return - 1 ; }
VIDIOC_QUERYCAP:查詢驅動功能
struct v4l2_capability cap; if ( ioctl(fd,VIDIOC_QUERYCAP,&cap) == - 1 ) printf( " error\n " ); printf( " capability:\n " ); printf( " driver:%s\n " ,cap.driver); printf( " card:%s\n " ,cap.card); printf( " bus info:%s\n " ,cap.bus_info); printf( " version:%d\n " ,cap.version); printf( " capabilities:%x\n " ,cap.capabilities);
VIDIOC_ENUM_FMT:獲取當前驅動支持的視頻格式
struct v4l2_fmtdesc fmtdesc; fmtdesc.index = 0 ; fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; printf( " fmtdesc:\n " ); while (ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc) != - 1 ) { printf( " \t%d.%s\n " ,fmtdesc.index+ 1 ,fmtdesc.description); fmtdesc.index ++ ; }
VIDIOC_G/S_FMT:讀取/設置當前驅動的視頻捕捉格式
struct v4l2_format format; memset( &format, 0 , sizeof ( struct v4l2_format)); format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if ( ioctl(fd, VIDIOC_G_FMT, &format) == - 1 ) { printf( " VIDIOC_G_FMT error\n " ); return - 1 ; } struct v4l2_pix_format pix_format; pix_format = format.fmt.pix; printf( " pix_format\n " ); printf( " width:%d\n " ,pix_format.width); printf( " height:%d\n " ,pix_format.height); printf( " bytesperline:%d\n " ,pix_format.bytesperline); printf( " sizeimage:%d\n " ,pix_format.sizeimage);
VIDIOC_TRY_FMT:驗證當前驅動的顯示格式
VIDIOC_CROPCAP:查詢驅動的修剪能力
VIDIOC_G/S_CROP:讀取/設置視頻信號的邊框
struct v4l2_cropcap cropcap; struct v4l2_crop crop; cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if ( 0 == ioctl(fd, VIDIOC_CROPCAP, & cropcap)) { crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; crop.c = cropcap.defrect; if (- 1 == ioctl(fd, VIDIOC_S_CROP, & crop)) { printf( " VIDIOC_S_CROP error\n " ); return - 1 ; } }
VIDIOC_QBUF:把緩存區放入緩存隊列
VIDIOC_DQBUF:把緩存去從緩存隊列中取出
unsigned int i; enum v4l2_buf_type type; for (i = 0 ; i< 4 ; ++ i) { struct v4l2_buffer buf; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; ioctl (fd,VIDIOC_QBUF, & buf); } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ioctl (fd,VIDIOC_STREAMON, & type); struct v4l2_buffer buf; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; if ( ioctl (fd,VIDIOC_DQBUF, &buf)==- 1 ) { printf( " error in VIDIOC_DQBUF\n " ); return - 1 ; }
VIDIOC_STREAMON:開始視頻顯示函數
VIDIOC_STREAMOFF:結束視頻顯示函數
VIDIOC_QUERYSTD:檢查當前視頻設備支持的標準,亞洲一般使用PAL制式攝像頭,歐洲一般使用NTSC攝像頭
v4l2_std_id std; int ret; do { ret = ioctl(fd,VIDIOC_QUERYSTD,& std); } while (- 1 ==ret && errno== EAGAIN); switch (std) { case V4L2_STD_NTSC: // case V4L2_STD_PAL: // }
處理v4l2視頻數據
v4l2設定了三種應用程序與驅動的交互方式:
1)直接讀取設備文件方式read/write
2)mmap映射方式
3)用戶指針方式
mmap方式:驅動將內部數據空間映射到應用程序空間上,雙方直接在這個空間上進行數據交換
用戶指針方式:首先由應用程序申請一段緩沖區,然后將緩沖區傳給驅動,驅動將其作為緩沖區,從而實現內存共享
直接read/write:一般配合select使用,直接讀取設備文件的方式進行I/O
關閉設備
調用close關閉文件描述符,如果進行了內存映射,關閉之前還需要munmap解除映射
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
