v4l2驱动编写篇第四--输入输出
1、输入和输出
这是不定期发布的关于写视频驱动程序的LWN系统文章的第四篇.没有看过介绍篇的,也许想从这里开始。本周的文章介绍的是应用程序如何确定在特定适配器上哪些输入和输出可用,并且在它们之间做出选择。
在很多情况下,视频适配器并不能提供很多的输入输出选项。比如说摄像头控制器,可能只是提供摄像头,而没什么别的功能。然而,在一些其他的情况下,事情将变得很复杂。一个电视卡可能对应板上不用的接头有不同的输入。他甚至可能有可以独立发挥其功能的多路调谐器。有时,那些输入会有不同的特性;有些调谐器可以支持比其他的更广泛的视频标准。对于输出来说,也有同样的问题。
很明显,若想一个应用可以有效地利用视频适配器,它必须有能力找到可用的输入和输出,而且他必须能找到他想操作的那一个。为此,Video4Linux2 API提供三种不同的ioctl()调用来处理输入,相应地有三个来处理输出。
这三个(对于硬件支持的每一个功能)驱动都要支持。虽然如此,对于简单的硬件而言,代码还是很简单的。驱动也要提供一此启动时的默认值。然而,驱动不应该做的是,在应用退出时重置输入输出信息。对于其他视频参数,在多次打开之间,参数应维持不变。
2、视频标准
在我们进入输入输出的细节之前,我们应该先了解一下视频标准。这些标准描述的是视频为进行传输而做出的格式转换–分辨率,帧频率等。这些标准通常是由每一个国家的监管部门制定的。现在世界上使标准主要的有三 个:NTSC(主要是北美使用)、PAL(主要是欧洲,非洲和中国)和SECAM(法,俄和非洲部分地区)。然而这在标准在国家之间都有变化,而且有些设备比其他设备能更加灵活,能与更多的标准变种协同工作。
V4L2使用v4l2_std_id来代表视频标准,它是一个64位的掩码。每个标准变种在掩码中就是一位。所以标准NTSC就是V4L2_STD_NTSC_M,值为0x1000,而日本的变种就是V4L2_STD_NTSC_M_JP(0x2000)。如果一个设备可以处理所以有NTSC变种,它就可以设为V4L2_STD_NTSC,它可以所有相关位置位。对PAL和SECAM标准,也存在一组类似的位集。
对于用户空间而言,V4L2提供一个ioctl()命令(VIDIOC_ENUMSTD),它允许应用查询设备实现了哪些标准。驱动却无需直接回答查询,而是将 video_device结构体的tvnorm字段设置为它所支持的所有标准。然后V4L2层会向应用输出所支持的标准。VIDIOC_G_STD命令, 可以用来查询现在哪种标准是激活的,它也是在V4L2层通过返回video_device结构的current_norm字段来处理的,驱动程序应在启动时,初始化current_norm来反应当前的情况。有些应用发现标准没有设置也会混乱,即使他并没有设置过标准。
当某个应用想要申请某个标准的时候,会发出一个VIDIOC_S_STD调用,该调用通过下面的函数传到驱动:
int (*vidioc_s_std) (struct file *file, void *private_data, v4l2_std_id std);
驱动要对硬件编程,以使用给定的标准,并返回0(或是负的出错编码。V4L2层需要把current_norm设为新的值。
应用可能想要知道硬件所看到的是何种输入信号,答案可以通过VIDIOC_QUERYSTD找到,它到了驱动里面就是:
int (*vidioc_querystd) (struct file *file, void *private_data, v4l2_std_id *std);
驱动要尽可能地在这个字段填写详细信息。如果硬件没有提供足够的信息,std字段就会暗示任何可能出现的标准。
这里还有一 点值得一提:所有的视频设备必须支持(或是声明支持)至少一种视频标准。视频标准对于摄像头来说没什么意义,它不与任何监管制度绑定。但是也不存一个标准 说“我是个摄像头,我什么都能做”,所以V4L2层有很多摄像头声明可以返回PAL或NTSC数据(实际只是如些声明而己)。
3、输入
视频捕获的应用首先要通过VIDIOC_ENUMINPUT命令来枚举所有可用的输入。在V4L2层,这个调用会转换成调用一个驱动中对应的回调函数:
int (*vidioc_enum_input)(struct file *file, void *private_data, struct v4l2_input *input);
在这个调用中,file 对就的是打开的视频设备。private_data是驱动的私有字段,input字段是真正的传递的信息,它有如下几个值得关注的字段:
•__u32 index:应用关注的输入的索引号; 这是惟一一个用户空间设定的字段。驱动要分配索引号给输入,从0开始,依次往上增加。应用想要知道所有可用的输入时,要调用VIDIOC_ENUMINPUT 控制,调用索引号从0开始,并开始递增。 一旦返回EINVAL,应用就知道,输入己经遍历结束了,只要有输入,输入索引号0就一定要存在的。
•__u8 name[32]: 输入的名字,由驱动设定。简单起见,可以设为”Camera”,诸如此类;如果卡上有多个输入,名称就要与接口的打印相符合.
•__u32 type:输入的类型,现在只有两个值可选:V4L2_INPUT_TYPE_TUNER和V4L2_INPUT_TYPE_CAMERA.
•__u32 audioset:描述哪个音频输入可以与些视频输入相关联. 音频输入与视频输入一样通过索引号枚举 (我们会在另一篇文章中关注音频),但并非所以的音频与视频的组合都是可用的.这个字段是一个掩码,代表对于当前枚举出的视频而言,哪些音频输入是可以与 之关联的.如果没有音频输入可以与之关联,或是只有一个可选,那么就可以简单地把这个字段置0.
•__u32 tuner: 如果输入是一个调谐器 (type字段置为V4L2_INPUT_TYPE_TUNER), 这个字段就是会包含一个相应的调谐设备的索引号.枚举和调谐器的控制也将在未来的文章中讲述.
•v4l2_std_id std: 描述设备支持哪个或哪些视频标准.
•__u32 status: 给出输入的状态. 完整的标识符集合可以在V4L2的文档中找到(即这里
);简而言之,status中设置的每一位都代表一个问题. 这些问题包括没有电源,没有信号,没有同频锁,或 the presence of Macrovision(这个是什么意思?没查到)或是其他一些不幸的问题.
•__u32 reserved[4]:保留字段,驱动应该将其置0.
通常驱动会设置上面所以的字段,并返回0。如果索引值超出支持的输入范围,应该返回-EINVAL.这个调用里可能出现的错误不多。
当应用想改变当前的输入时,驱动会收到一个对回调函数vidioc_s_input()的调用。
int (*vidioc_s_input) (struct file *file, void *private_data, unsigned int index);
index的值与上面讲到的意义相同 – 它用来确定哪个输入是应用想要的,驱动要对硬件进行设置,选择那个输入并返回0.也有可能要返回-EINVAL(索引号不正确时) 或-EIO(硬件有问题). 即使只有一路输入,驱动也要实现这个回调函数。还有另一个回调函数,指示哪一个输入是激活状态的:
int (*vidioc_g_input) (struct file *file, void *private_data, unsigned int *index);
这里驱动把index值设为对应的输入的索引号.
4、输出
枚举和选择输出的过程与输入的是十分相似的。所以这里的描述就从简。输出枚举的回调函数是这样的:
int (*vidioc_enumoutput) (struct file *file, void *private_data ,struct v4l2_output *output);
v4l2_output
结构的字段是:
•__u32 index:相关输入的索引号.其工作方式与输入的索引号相同:它从0开始递增。
•__u8 name[32]: 输出的名字.
•__u32 type: 输入的类型.支持的输出类型为:V4L2_OUTPUT_TYPE_MODULATOR
用于模拟电视调制器,V4L2_OUTPUT_TYPE_ANALOG
用于基本模拟视频输出,和V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY
用于模拟VGA覆盖设备.
•__u32 audioset: 能与这个视频协同工作的音频集.
•__u32 modulator: 与此设备相关的调制器 (对于类型为V4L2_OUTPUT_TYPE_MODULATOR 的设备而言).
•v4l2_std_id std:输出所支持的视频标准.
•__u32 reserved[4]: 保留字段,要设置为0.
也有用于获得和设定现行输入设置的回调函数;他们与输入的具体对称性:
int (*vidioc_g_output) (struct file *file, void *private_data, unsigned int *index);
int (*vidioc_s_output) (struct file *file, void *private_data, unsigned int index);
即便只有一个输出,设备驱动也要定义所有上述的三个回调函数.
有了这些函数之后,V4L2应用就可以知道有哪些输入和输入,并在它们间进行选择.然而选译这些输入输出中所传输的是什么视频数据流则是一件更加复杂的事情.本系列的下一期文章,我们将关注视频数据流的格式,以及如何与用户空间协定数据格式.