Linux - 使用V4L2(总结)

一、 什么是V4L2

概述: Video for linux 2(简称V4L2),是linux中关于视频设备的内核驱动
它也是 linux操作系统下用于采集图片、视频和音频数据的 API接口,配合适当的视频采集设备和相应的驱动程序;

作用: 支持许多USB 网络摄像头,电视调谐器和相关设备,使它们的输出标准化,因此程序员可以轻松地向其应用程序添加视频支持。MythTV,tvtime和Tvheadend是使用V4L框架的典型应用程序;
可以实现图片、视频、音频等的采集。在远程会议、可视电话、视频监控系统和嵌入式多媒体终端中都有广泛的应用。

存放位置: Linux中,一切皆文件,视频设备为设备文件,可以像普通文件一样进行读写操作,而采用 V4L2驱动的摄像头设备文件是 /dev/v4l/video0,为了通用,可以建立到一个和普通摄像头一样的 /dev/video0的链接。

V4L2 架构图如下:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

二、 什么是ioctl

概述: ioctl是设备驱动程序中对设备的 I/O通道进行管理的接口函数
所谓对 I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等。

作用: 一个字符设备驱动通常会实现设备打开、关闭、读、写等功能,在一些需要细分的情境下,如果需要扩展新的功能,通常以增设 ioctl() 命令的方式实现。例:当你用 read,write不能完成某一功能时,就用 ioctl来操作。
配合一些头文件(v4l2-controls.h / videodev2.h),根据命令,实现对摄像头的操作,如:白平衡、聚焦、曝光、饱和度、亮度…

函数:

#include <sys/ioctl.h>  //需要引用的头文件

//参数一:文件描述符
//参数二:设备驱动命令,执行对应操作
//参数三:根据参数二变化
int ioctl(int fd, int cmd, ...) ;

在这里插入图片描述

三、 操作流程

  1. 打开设备文件。(int fd=open("/dev/video0",O_RDWR);)

  1. 查询设备属性:取得设备的capability,看看设备具有什么功能,比如是否具有视频输入,或者音频输入输出等。(ioctl(fd_v4l, VIDIOC_QUERYCAP, &cap);)

  1. 选择视频输入,一个视频设备可以有多个视频输入。(VIDIOC_S_INPUT, struct v4l2_input)

  1. 设置视频采集的参数。 —设置视频的制式,制式包括PAL/NTSC,使用 ioctl(fd_v4l, VIDIOC_S_STD, &std_id)
    —设置视频图像的采集窗口的大小,使用 ioctl(fd_v4l, VIDIOC_S_CROP, &crop)
    —设置视频帧格式,包括帧的点阵格式,宽度和高度等,使用 ioctl(fd_v4l, VIDIOC_S_FMT, &fmt)
    —设置视频的帧率,使用 ioctl(fd_v4l, VIDIOC_S_PARM, &parm)
    —设置视频的旋转方式,使用 ioctl(fd_v4l, VIDIOC_S_CTRL, &ctrl)

  1. 向驱动申请帧缓冲,一般不超过5个。(ioctl(fd_v4l, VIDIOC_REQBUFS, &req);)

  1. 查询帧缓冲区在内核空间中的长度和偏移量 (ioctl(fd_v4l, VIDIOC_QUERYBUF, &buf);)

  1. 将申请到的帧缓冲映射到用户空间 mmap,这样就可以直接操作采集到的帧了,而不必去复制。(buffers[i].start = mmap (NULL, buffers[i].length, PROT_READ | PROT_WRITE, MAP_SHARED,fd_v4l, buffers[i].offset); )

  1. 将申请到的帧缓冲全部入队列,以便存放采集到的数据。(ioctl (fd_v4l, VIDIOC_QBUF, &buf) )

  1. 开始视频的采集。(ioctl (fd_v4l, VIDIOC_STREAMON, &type) )

  1. 出队列以取得已采集数据的帧缓冲,取得原始采集数据。(ioctl (fd_v4l, VIDIOC_DQBUF, &buf) )

  1. 处理完后, 将该帧缓冲重新入队列尾,这样可以循环采集(循环步骤8-10),直到停止采集。

  1. 停止视频的采集。(ioctl (fd_v4l, VIDIOC_STREAMOFF, &type) ;)

  1. 释放申请的视频帧缓冲区 unmap,关闭视频设备。(close(fd_v4l);)

在这里插入图片描述

1. 打开设备文件

  • 阻塞模式 / 非阻塞模式

—应用程序能够使用阻塞模式或非阻塞模式,打开视频设备。

阻塞操作: 是指在执行设备操作时,若不能获得资源,则挂起进程直到满足操作条件后再进行操作。被挂起的进程进入休眠(不占用cpu资源),被从调度器移走,直到条件满足。在设备驱动中,阻塞的实现通常是通过等待队列。

非阻塞操作: 如果使用非阻塞模式调用视频设备,在不能进行设备操作时,并不挂起或者放弃,或者不停地查询,直到可以进行操作(一直占用CPU资源)。即使尚未捕获到信息,驱动依旧会把缓存(DQBUFF)里的东西返回给应用程序。
非阻塞应用程序通常使用 select系统调用查询是否可以对设备进行无阻塞的访问,最终会引发设备驱动中 poll函数执行。

(建议 V4L2编程中使用阻塞方式打开一个设备文件,除非你能保重开始采集数据时队列里的n块缓存已有数据存在。)


  • 用非阻塞模式打开摄像头设备
int cameraFd = open(/dev/video0″, O_RDWR| O_NONBLOCK, 0);
  • 用阻塞模式打开摄像头设备
int cameraFd = open(/dev/video0″, O_RDWR, 0);

若出现错误:error: VIDIOC_DQBUF: Resource temporarily unavailable

在这里插入图片描述

2. 查询设备属性(VIDIOC_QUERYCAP)

函数使用:int ioctl(int fd, int request, struct v4l2_capability *argp);
  • v4l2相关结构体定义:
struct v4l2_capability
{
   
	u8 driver[16]; // 驱动名字
	u8 card[32]; // 设备名字
	u8 bus_info[32]; // 设备在系统中的位置
	u32 version;// 驱动版本号
	u32 capabilities;// 设备支持的操作
	u32 reserved[4]; // 保留字段
};

capabilities 常用值:

  • V4L2_CAP_VIDEO_CAPTURE (是否支持图像获取)
struct v4l2_capability cap;
ioctl(fd,VIDIOC_QUERYCAP,&cap);
printf(“Driver Name:%s\nCard Name:%s\nBus info:%s\nDriver Version:%u.%u.%u\n”,cap.driver,cap.card,cap.bus_info,cap.capabilities);
  • V4L2_BUF_TYPE_VIDEO_CAPTURE (获取设备支持的分辨率)

例一:

    enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//初始化
    struct v4l2_fmtdesc fmt_1;
    struct v4l2_frmsizeenum frmsize;
    struct v4l2_frmivalenum frmival;
    fmt_1.index = 0; //索引
    fmt_1.type = type;
    
    while (ioctl(fd, VIDIOC_ENUM_FMT, &fmt_1
  • 60
    点赞
  • 398
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值