经过了一周的V4L2(video for linux two)的学习,终于用摄像头采集到视频图像了。接下来整理一下我的学习过程。
首先介绍一下开发环境:
主机win7 + 虚拟机ubuntu + 广州斯道科技有限公司出品的Icool6410,采用交叉编译的方式,使用命令arm-linux-gcc –ccamara.c –o camtest将编译好的文件复制到win7上,再使用ftp挂载开发板(这个需要把开发板连接路由器,然后autoeth0查看路由器分配给开发板的IP,然后打开win7我的电脑运行ftp://IP,就可以挂载开发板了),把生成的执行文件camtest复制到开发板文件系统中,然后再修改文件权限chmod 777 camtest,再运行./camtest就可以生成一个out.yuv文件,再从开发板文件系统中把文件复制到win7上,然后再使用软件YUV viewer打开out.yuv文件,就可以看到摄像头采集到的图片了。
接下来介绍一下常用的结构体:
structv4l2_requestbuffers //申请帧缓冲,对应命令VIDIOC_REQBUFS
struct v4l2_capability //视频设备的功能,对应命令VIDIOC_QUERYCAP
structv4l2_input //视频输入信息,对应命令VIDIOC_ENUMINPUT
structv4l2_standard //视频的制式,比如PAL,NTSC,对应命令VIDIOC_ENUMSTD
structv4l2_format //帧的格式,对应命令VIDIOC_G_FMT、VIDIOC_S_FMT等
structv4l2_buffer //驱动中的一帧图像缓存,对应命令VIDIOC_QUERYBUF
structv4l2_crop //视频信号矩形边框
structv4l2_std_id //视频制式
这些结构在都在include/linux/videodev2.h中定义,想详细了解这些结构体的可以去看看这个头文件。
2、常用的IOCTL接口命令也在include/linux/videodev2.h中定义
VIDIOC_REQBUFS//分配内存
VIDIOC_QUERYBUF//把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址
VIDIOC_QUERYCAP//查询驱动功能
IDIOC_ENUM_FMT//获取当前驱动支持的视频格式
VIDIOC_S_FMT//设置当前驱动的频捕获格式
VIDIOC_G_FMT//读取当前驱动的频捕获格式
VIDIOC_TRY_FMT//验证当前驱动的显示格式
VIDIOC_CROPCAP//查询驱动的修剪能力
VIDIOC_S_CROP //设置视频信号的矩形边框
VIDIOC_G_CROP //读取视频信号的矩形边框
VIDIOC_QBUF //把数据从缓存中读取出来
VIDIOC_DQBUF //把数据放回缓存队列
VIDIOC_STREAMON //开始视频显示函数
VIDIOC_STREAMOFF //结束视频显示函数
VIDIOC_QUERYSTD //检查当前视频设备支持的标准,例如PAL或NTSC
3. V4L2拥有一套标准的API,大家在做应用程序的时候应该多使用官方提供的接口函数。关于视频采集是有一定的顺序的。
(1)首先要打开摄像头设备文件,这里的前提是开发板一定要有摄像头对应的驱动,若没有就需要移植相应的驱动到内核了。然后使用命令查看开发板是否有/dev/video0这个文件,若有就证明可以打开摄像头了。
使用fd = open(dev_name, O_RDWR /* required */| O_NONBLOCK, 0) 可读可写、无阻塞的的方式打开摄像头文件,则当没有可用的视频数据时,不会阻塞,而立刻返回.
(2)检查当前视频设备支持的标准
do {
structv4l2_std_id std;ê?
ret =ioctl(fd, VIDIOC_QUERYSTD, &std);
} while (ret == -1 && errno ==EAGAIN);
switch (std) {
caseV4L2_STD_NTSC:
printf("thedevice support NTSC\n");
caseV4L2_STD_PAL:
printf("thedevice support STD_PAL\n");
}
(3)取得设备的capability 。
structv4l2_capability capability;
int ret =ioctl(fd, VIDIOC_QUERYCAP, &capability);
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
fprintf(stderr, "%s is no video capture device \n",dev_name);
if (!(cap.capabilities & V4L2_CAP_S