Video for Linux Two:V4L2的是V4L的第二个版本。原来的V4L被引入到Linux内核2.1.x的开发周期后期。Video4Linux2修正了一些设计缺陷,并开始出现在2.5.X内核。Video4Linux2驱动程序包括Video4Linux1应用的兼容模式,但实际上,支持是不完整的,并建议V4L2的设备使用V4L2的模式。现在,该项目的DVB-Wiki托管在LinuxTV的网站上。 要想了解 V4l2 有几个重要的文档是必须要读的,Documentation/video4linux目录下的V4L2-framework.txt和videobuf、V4L2的官方API文档V4L2 API Specification 、drivers/media/video目录下的vivi.c(虚拟视频驱动程序 -此代码模拟一个真正的视频设备V4L2 API)。
V4l2可以支持多种设备,它可以有以下几种接口:
1. 视频采集接口(video capture interface):这种应用的设备可以是高频头或者摄像头.V4L2的最初设计就是应用于这种功能的.
2. 视频输出接口(video output interface):可以驱动计算机的外围视频图像设备--像可以输出电视信号格式的设备.
3. 直接传输视频接口(video overlay interface):它的主要工作是把从视频采集设备采集过来的信号直接输出到输出设备之上,而不用经过系统的CPU.
4. 视频间隔消隐信号接口(VBI interface):它可以使应用可以访问传输消隐期的视频信号.
5. 收音机接口(radio interface):可用来处理从AM或FM高频头设备接收来的音频流.
在Linux系统中,V4L2驱动的Video设备节点路径通常/dev/video/中的videoXV4L2驱动对用户空间提供字符设备,主设备号为81,对于视频设备,其次设备号为0-63。除此之外,次设备号为64-127的Radio设备,次设备号为192-223的是Teletext设备,次设备号为224-255的是VBI设备。
V4L2 的驱动源码在 drivers/media/video目录下,主要核心代码有:
v4l2-dev.c //linux版本2视频捕捉接口,主要结构体 video_device 的注册
v4l2-common.c //采用低级别的操作一套设备structures/vectors的通用视频设备接口。
//此文件将替换videodev.c的文件配备常规的内核分配。
v4l2-device.c //V4L2的设备支持。注册v4l2_device
v4l22-ioctl.c //处理V4L2的ioctl命令的一个通用的框架。
v4l2-subdev.c //v4l2子设备
v4l2-mem2mem.c //设备的辅助函数,使用其源和目的地videobuf缓冲区。
头文件linux/videodev2.h、media/v4l2-common.h、media/v4l2-device.h、media/v4l2-ioctl.h、media/v4l2-dev.h、media/v4l2-ioctl.h等。
1.V4l2_device
struct V4l2_device{
struct device *dev;/* DEV-> driver_data指向这个结构。*/
struct list_head subdevs;/* 用于跟踪注册的subdevs */
spinlock_t lock; /*锁定此结构体;可以使用的驱动程序以及如果这个结构嵌入到一个更大的结构。 */
char name[V4L2_DEVICE_NAME_SIZE];/* 独特的设备名称,默认情况下,驱动程序姓名+总线ID */
void (*notify)(struct v4l2_subdev *sd,/*报告由一些子设备调用的回调函数。 */
unsigned int notification, void *arg);
};
2.struct video_device
struct video_device
{
const struct v4l2_file_operations *fops;/*设备操作函数 */
struct device dev; /* v4l 设备 */
struct cdev *cdev; /* 字符设备 */
struct device *parent; /*父设备 */
struct v4l2_device *v4l2_dev; /* v4l2_device parent */
/* 设备信息 */
char name[32];
int vfl_type;
/* 'minor' is set to -1 if the registration failed */
int minor;
u16 num;
/* use bitops to set/clear/test flags */
unsigned long flags;
/*属性来区分一个物理设备上的多个索引 */
int index;
/* V4L2 文件句柄 */
spinlock_t fh_lock; /*锁定所有的 v4l2_fhs */
struct list_head fh_list; /* List of struct v4l2_fh */
int debug; /* Activates debug level*/
/* Video standard vars */
v4l2_std_id tvnorms; /* Supported tv norms */
v4l2_std_id current_norm; /* Current tvnorm */
/* 释放的回调函数 */
void (*release)(struct video_device *vdev);
/* 控制的回调函数 */
const struct v4l2_ioctl_ops *ioctl_ops;
}
fops:设置这个v4l2_file_operations结构,file_operations的一个子集。v4l2_dev: 设置这个v4l2_device父设备
name:
ioctl_ops:使用v4l2_ioctl_ops简化的IOCTL,然后设置v4l2_ioctl_ops结构。
lock:如果你想要做的全部驱动程序锁定就保留为NULL。否则你给它一个指针指向一个mutex_lock结构体和任何v4l2_file_operations被调用之前核心应该释放释放锁。
parent:一个硬件设备有多个PCI设备,都共享相同v4l2_device核心时,设置注册使用NULL v4l2_device作为父设备结构。
flags:可选的。设置到V4L2_FL_USE_FH_PRIO如你想让框架处理VIDIOC_G/ S_PRIORITY的ioctl。这就需要您使用结构v4l2_fh。这个标志最终会消失,一旦所有的驱动程序使用的核心优先处理。但现在它必须明确设定。
如果使用v4l2_ioctl_ops,那么你应该设置。unlocked_ioctlvideo_ioctl2在v4l2_file_operations结构。
3.v4l2_subdev
struct v4l2_subdev {
#if defined(CONFIG_MEDIA_CONTROLLER)
struct media_entity entity;
#endif
struct list_head list;
struct module *owner;
u32 flags;
struct v4l2_device *v4l2_dev;
const struct v4l2_subdev_ops *ops;
/* 从驱动程序中不要调用这些内部操作函数! */
const struct v4l2_subdev_internal_ops *internal_ops;
/*这个subdev控制处理程序。可能是NULL。 */
struct v4l2_ctrl_handler *ctrl_handler;
/* 名字必须是唯一 */
char name[V4L2_SUBDEV_NAME_SIZE];
/* 可用于到类似subdevs组,值是驱动程序特定的 */
u32 grp_id;
/* 私有数据的指针 */
void *dev_priv;
void *host_priv;
/* subdev 设备节点*/
struct video_device devnode;
/* 事件的数量在打开的时候被分配 */
unsigned int nevents;
};
每个子设备驱动程序必须有一个v4l2_subdev结构。这个结构可以独立简单的设备或者如果需要存储更多的状态信息它可能被嵌入在一个更大的结构。由于子设备可以做很多不同的东西,你不想结束一个巨大的OPS结构其中只有少数的OPS通常执行,函数指针进行排序按类别,每个类别都有其自己的OPS结构。顶层OPS结构包含的类别OPS结构,这可能是NULL如果在subdev驱动程序不支持任何从该类别指针。
4.v4l2_buffer
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;
/* memory location */
enum v4l2_memory memory;
union {
__u32 offset;
unsigned long userptr;
} m;
__u32 length;
__u32 input;
__u32 reserved;
};
V4L2核心API提供了一套标准方法的用于处理视频缓冲器(称为“videobuf”)。这些方法允许驱动程序以一致的方式来实现read(),mmap()和overlay()。目前使用的设备上的视频缓冲器,支持scatter/gather方法(videobuf-dma-SG),线性存取的DMA的(videobuf-DMA-contig),vmalloc分配的缓冲区,主要用于在USB驱动程序(DMA缓冲区的方法videobuf-vmalloc)。 videobuf层的功能为一种V4L2驱动和用户空间之间的粘合层。它可以处理存储视频帧缓冲区的分配和管理。有一组可用于执行许多标准的POSIX I / O系统调用的功能,包括read(),poll()的,happily,mmap()。另一套功能可以用来实现大部分的V4L2的ioctl()调用相关的流式I/ O的,包括缓冲区分配,排队和dequeueing,流控制。驱动作者使用videobuf规定了一些设计决定,但回收期在驱动器和一个V4L2的用户空间API的贯彻实施在减少代码的形式。 关于videobuf的层的更多信息,请参阅Documentation/video4linux/videobuf。
/*第一个参数‘dev’通常是一个pci_dev的struct device的指针,但它是ISA设备或一个设备创建多个PCI设备时这是罕见的DEV为NULL,因此makingit不可能联想到一个特定的父母v4l2_dev。 您也可以提供一个notify()回调子设备,可以通过调用通知你的事件。取决于你是否需要设置子设备。一个子设备支持的任何通知必须在头文件中定义 .注册时将初始化 v4l2_device 结构体. 如果 dev->driver_data字段是空, 它将连接到 v4l2_dev.*/
v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);
v4l2_device_unregister(struct v4l2_device *v4l2_dev);
struct video_device *vdev = video_device_alloc();
video_register_device(struct video_device *vdev, int type, int nr);
/* vdev:我们要注册的视频设备结构。type:设备类型注册nr:设备号(0==/dev/video0,1??== /dev/video1,...-1==释放第一个)warn_if_nr_in_use:如果所需的设备节点号码已经在使用另一个号码代替选择。*/
__video_register_device(struct video_device *vdev, int type, int nr,int warn_if_nr_in_use)
video_unregister_device(struct video_device *vdev);