1。 video for linux 现在是第2版
2。 号称是支持multiple
opens,当然前提是这多个open最好不要是在都要进行数据传输的情况下的,比如一个process可以控制它的一些参数,一个process在进行在线的video
recoding。
3。 Shared Data Streams
数据流的共享,建议是在应用级去实现,在底层我们用一个proxy单独去管理获取数据,再上层,多个人去与proxy通信,达到数据流的共享。与底层透明。
4。主要使用的操作就是open, close, ioctl
5. Querying Capabilities
虽然这是个标准,但不是强制性的,因此不同的设备对功能的支持不同,所以地提供一个功能查询机制,而这个功能查询机制应该是必需的。All
V4L2 drivers must support VIDIOC_QUERYCAP. Applications should always call
this ioctl after opening the device
6。Application Priority
既然允许multiple
opens,那么不同的任务之间应该有个优先级,来处理一些具有conflict的情况,可以使用
VIDIOC_S_PRIORITY和VIDIOC_G_PRIORITY
的ioctl操作分别来设置和查询当前任务的优先级。据个例子,如果你要通过
VIDIOC_S_INPUT修改driver的属性,你可能由于已经存在了另一个具有较高优先级的任务而导致,你这次修改失败,你总不能把高优先级的任务影响了吧。
7。Video Inputs and Outputs
一个device可以接好多个connectors,如RGB,DVI, CVBS,
S-Video接口,因此它有多个输入或输出,那么有几个可用,当前在用哪个?他是什么类型呢?这些都是可以查看的。下面是CVBS的概念:
中文解释:复合视频广播信号 或 复合视频消隐和同步
全称:Composite Video Broadcast Signal 或Composite Video Blanking and Sync
它是的一个模拟电视节目(图片)信号在与声音信号结合,并调制到射频载波之前的一种格式。
CVBS是"Color, Video, Blank and Sync", "Composite Video Baseband Signal",
"Composite Video Burst Signal", or "Composite Video with Burst and
Sync".的缩写
CVBS
是被广泛使用的标准,也叫做基带视频或RCA视频,是全国电视系统委员会(NTSC)电视信号的传统图像数据传输方法,它以模拟波形来传输数据。复合视频包含色差(色调和饱和度)和亮度(光亮)信息,并将它们同步在消隐脉冲中,用同一信号传输。
在快速扫描的NTSC电视中,甚高频(VHF)或超高频(UHF)载波是复合视频所使用的调整振幅,这使产生的信号大约有6MHz宽。一些闭路电视系统使用同轴电缆近距离传输复合视频,一些DVD播放器和视频磁带录像机(VCR)通过拾音插座提供复合视频输入和输出,这个插座也叫做RCA连接器。
复合视频中,色差和亮度信息的干涉是不可避免的,特别是在信号微弱的时候。这就是为何远距离的使用VHF或UHF的NTFS电视台用老旧的鞭形天线,"兔子耳朵",或世外的"空中"经常包含假的或上下摇动的颜色。CVBS又叫RCA是一种比较低级的模拟信号的传输标准,用一条线传输视频,亮度和色度混合,失真严重,我们常看到的三接头的电视中的黄色接头就是CVBS接头,其他两个对应2个声道的音频。注意,色度应该是可以分离出色差和饱和度信号的,具体有待进一步研究。
言归正传,我们可以通过VIDIOC_ENUMINPUT and VIDIOC_ENUMOUTPUT
分别列举一个input或者output的信息,我们使用一个v4l2_input结构体来乘放查询结果,这个结构体中有一个index域用来指定你索要查询的是第几个input/ouput,如果你所查询的这个input是当前正在使用的,那么在v4l2_input还会包含一些当前的状态信息,如果所查询的input/output不存在,那么回返回EINVAL错误,所以,我们通过循环查找,直到返回错误来遍历所有的input/output.
VIDIOC_G_INPUT and VIDIOC_G_OUTPUT 返回当前的video input和output的index.
Example 1-1. Information about the current video input
struct v4l2_input input; int index; if (-1 == ioctl (fd, VIDIOC_G_INPUT,
&index)) { perror ("VIDIOC_G_INPUT"); exit (EXIT_FAILURE); } memset
(&input, 0, sizeof (input)); input.index = index; if (-1 == ioctl (fd,
VIDIOC_ENUMINPUT, &input)) { perror ("VIDIOC_ENUMINPUT"); exit
(EXIT_FAILURE); } printf ("Current input: %s\n",
input.name);
Example 1-2. Switching to the first video input
int index; index = 0; if (-1 == ioctl (fd, VIDIOC_S_INPUT, &index)) {
perror ("VIDIOC_S_INPUT"); exit (EXIT_FAILURE); }
Video standards
当然世界上现在有多个视频标准,如NTSC和PAL,他们又细分为好多种,那么我们的设备输入/输出究竟支持什么样的标准呢?我们的当前在使用的输入和输出正在使用的是哪个标准呢?我们怎么设置我们的某个输入输出使用的标准呢?这都是有方法的。
(1)查询,我们的输入支持什么标准,首先就得找到当前的这个输入的index,然后查出它的属性,在其属性里面可以得到该输入所支持的标准,将它所支持的各个标准与所有的标准的信息进行比较,就可以获知所支持的各个标准的属性。一个输入所支持的标准应该是一个集合,而这个集合是用bit与的方式使用一个64位数字表示的。因此我们所查到的是一个数字。
Example 1-5. Information about the current video standard
v4l2_std_id std_id; //这个就是个64bit得数 struct v4l2_standard standard;
//VIDIOC_G_STD就是获得当前输入使用的standard,不过这里只是得到了该标准的id即flag,还没有得到其具体的属性信息,具体的属性信息要通过列举操作来得到。
if (-1 == ioctl (fd, VIDIOC_G_STD, &std_id)) {
//获得了当前输入使用的standard /* Note when VIDIOC_ENUMSTD always returns
EINVAL this is no video device or it falls under the USB exception, and
VIDIOC_G_STD returning EINVAL is no error. */ perror ("VIDIOC_G_STD");
exit (EXIT_FAILURE); } memset (&standard, 0, sizeof (standard));
standard.index = 0; //从第一个开始列举
//VIDIOC_ENUMSTD用来列举所支持的所有的video标准的信息,不过要先给standard结构的index域制定一个数值,所列举的标准的信息属性包含在standard
里面,如果我们所列举的标准和std_id有共同的bit,那么就意味着这个标准就是当前输入所使用的标准,这样我们就得到了当前输入使用的标准的属性信息
while (0 == ioctl (fd, VIDIOC_ENUMSTD, &standard)) { if (
standard.id &
std_id) { printf ("Current video standard: %s\n",
standard.name); exit
(EXIT_SUCCESS); } standard.index++; } /* EINVAL indicates the end of the
enumeration, which cannot be empty unless this device falls under the USB
exception. */ if (errno == EINVAL || standard.index == 0) { perror
("VIDIOC_ENUMSTD"); exit (EXIT_FAILURE); }
Example 1-6. Listing the video standards supported by the current input
struct v4l2_input input; struct v4l2_standard standard; memset (&input, 0,
sizeof (input));
//首先获得当前输入的index,注意只是index,要获得具体的信息,就的调用列举操作
if (-1 == ioctl (fd, VIDIOC_G_INPUT, &input.index)) { perror
("VIDIOC_G_INPUT"); exit (EXIT_FAILURE); }
//调用列举操作,获得input.index对应的输入的具体信息 if (-1 == ioctl (fd,
VIDIOC_ENUMINPUT, &input)) { perror ("VIDIOC_ENUM_INPUT"); exit
(EXIT_FAILURE); } printf ("Current input %s supports:\n",
input.name);
memset (&standard, 0, sizeof (standard)); standard.index = 0;
//列举所有的所支持的standard,如果
standard.id与当前input的input.std有共同的bit
flag,意味着当前的输入支持这个standard,这样将所有驱动所支持的standard列举一个遍,就可以找到该输入所支持的所有
standard了。 while (0 == ioctl (fd, VIDIOC_ENUMSTD, &standard)) { if
(
standard.id & input.std) printf ("%s\n",
standard.name);
standard.index++; } /* EINVAL indicates the end of the enumeration, which
cannot be empty unless this device falls under the USB exception. */ if
(errno != EINVAL || standard.index == 0) { perror ("VIDIOC_ENUMSTD"); exit
(EXIT_FAILURE); }
Example 1-7. Selecting a new video standard
struct v4l2_input input; v4l2_std_id std_id; memset (&input, 0, sizeof
(input)); //获得当前input的index if (-1 == ioctl (fd, VIDIOC_G_INPUT,
&input.index)) { perror ("VIDIOC_G_INPUT"); exit (EXIT_FAILURE); }
//列举出下标为input.index的input的属性到input里 if (-1 == ioctl (fd,
VIDIOC_ENUMINPUT, &input)) { perror ("VIDIOC_ENUM_INPUT"); exit
(EXIT_FAILURE); } //如果该input所支持的标准里不包含V4L2_STD_PAL_BG,就退出
if (0 == (input.std & V4L2_STD_PAL_BG)) { fprintf (stderr, "Oops. B/G PAL
is not supported.\n"); exit (EXIT_FAILURE); } /* Note this is also
supposed to work when only B or G/PAL is supported. */ std_id =
V4L2_STD_PAL_BG;
//如果当前input支持V4L2_STD_PAL_BG,就将其设置为V4L2_STD_PAL_BG if (-1 ==
ioctl (fd, VIDIOC_S_STD, &std_id)) { perror ("VIDIOC_S_STD"); exit
(EXIT_FAILURE); }
1。User
controlls其实就是一些用户可以用来进行设置的一些属性,如视频中的brightness等,video4linux就提取出了最常见的一些设置,给他们分配了ID,这样大家对于这些常见的设置,就是用这些ID就可以了,可以察看当前设备对该设置的值,也可以给该设置新值,此外,由于某些设置包含很多子设置项,因此就又有了menu的含义,即对于一个具体的control,我们在列举他的属性时,发现其类型是包含了menu的,那么我们就可以以这个control的id为参数,察看其menu及各自的值。当然用户可以由自定义的control以及extended
control。好像是Camera Control ID中就有可以设置focus聚焦的control
id,这个可以看一看。
2。Data format
应用是可以和device针对通信的数据进行谈判的,即可以设置device所使用的数据的格式,可以获得设备所使用的数据的格式,也可以尝试一下某种格式的数据设备是否支持。使用
VIDIOC_G_FMT and VIDIOC_S_FMT ioctls,而VIDIOC_TRY_FMT
就是用来试一下某设置是否被设备支持,而且只是测试,并不会起作用。我们还是可以用VIDIOC_ENUM_FMT来列举设备所支持的所有的image的格式的。关于数据格式,在video中就会涉及到image的格式,大小(宽度,高度),等信息。
3. crapping和scaling
就是把得到的数据作一定的剪裁,和伸缩,剪裁可以只取样我们可以得到的图像大小的一部分,剪裁的主要参数是位置和长度以及宽度,而scale的设置是通过VIDIOC_G_FMT
and VIDIOC_S_FMT 来获得和设置当前的image的长度,宽度来实现的。看下图
我们可以假设bounds是最大的能捕捉到的图像范围,defrect是我们的设备能够得到的最大的范围,这个可以通过VIDIOC_CROPCAP的ioctl来获得设备的crap相关的属性
v4l2_cropcap,其中的bounds就是这个bounds,其实就是上限。每个设备都有个默认的取样范围,就是defrect,就是default
rect的意思,它比bounds要小一些。这个范围也是通过VIDIOC_CROPCAP的ioctl来获得的
v4l2_cropcap结构中的defrect来表示的,我们可以通过 VIDIOC_G_CROP and
VIDIOC_S_CROP 来获取和设置设备当前的crop设置。
问题:难道设置VIDIOC_S_FMT只是设置了伸缩?即到的图像还是一样的?具体拍的哪部分要依靠设置crop的设置?