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元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

