官方文档地址:http://v4l2spec.bytesex.org/
$Chapter 1. Common API Elements
V4L2设备编程包含如下步骤:
1.打开设备
2.改变设备属性,选择一个video和audio输入、video标准、图片亮度等等
3.确定一个数据格式
4.确定一个输入输出方法;
5.实际的输入输出环(input/output loop)
6.关闭设备
在实际应用中,有些步骤可能是不需要的,或者无序的。
*1.1 关闭和打开设备
**1.1.1 设备名
#视频设备驱动,可能注册一个或多个设备节点。这些设备节点的主设备号是81,次设备号在0-255之间。
#一般用次设备号0和1,注册头两个视频捕获设备;
而用次设备号64和65,注册头两个radio设备。
**1.1.2 相关设备
#设备可以支持相关的功能:
video capturing, video overlay、 VBI capturing(/dev/vbi,Major:81,Minor224)、FM radio
/dev/video捕获视频图像;/dev/vbi捕获 raw VBI数据。
/dev/radio(81,64)在radio设备中是不变的,与video功能无关。
**1.1.3 同时打开(Multiple Opens)
#当一个应用程序在捕获视频和audio的同时,另一个应用程序可以改变亮度或声音。
Multiple opens应该允许并发使用设备。
应用程序使用优先级机制可以获得特权访问(Section 1.3)。
1.1.4 共享数据流(Shared Data Streams)
#V4L2 驱动应该不支持多应用程序同时通过拷贝buffers来读写同一个设备上的同一个数据流(data stream);
当驱动支持数据流共享,那么它必须被透明地实现。
*1.2 查询功能(Querying Capabilities)
#ioctl 的这个 “VIDIOC_QUERYCAP” 就是用来查询驱动支持哪些功能。所有的V4L2驱动必须支持“VIDIOC_QUERYCAP”,并且应用程序每次打开设备之后必须调用这个“VIDIOC_QUERYCAP”的ioctl。
*1.3 应用优先级(Application Priority)
#当多个应用程序共享一个设备时,那么就需要给他们分配不同的优先级。
#V4L2定义了“VIDIOC_G_PRIORITY”和“VIDIOC_S_PRIORITY”,分别用来查询和设置(s代表set,g代表get)访问的优先级(每个应用程序对应一个文件描述符)。
在使用“VIDIOC_QUERYCAP”验证了功能之后,应用程序再通过“VIDIOC_S_PRIORITY”请求一个优先级。
#在另一个应用程序获得了更高的优先级之后,一个应用程序改变驱动属性的操作如“VIDIOC_S_INPUT”,会返回一个EBUSY的错误。当然,有一个事件机制可以告诉这个应用程序,异步属性改变,可以添加了(但是你之前没有添加成功)。
*1.4. 视频输入输出(Video Inputs and Outputs)
#视频输入和输出是利用设备的物理连接器(天线、CVBS、S-Video和RGB接口等)来进行的。
#仅video和VBI捕获(capture)设备具有输入、输出设备,而Radio设备没有video输入和输出。
#要知道有效的输入输出的属性和数量,应用程序通过“VIDIOC_ENUMINPUT”和“VIDIOC_ENUMOUTPUT”可以枚举这些属性。
##相应的,struct v4l2_input 里的值,是由 ioctl(,VIDIOC_ENUMINPUT,&a_v4l2_input)来设置的。
struct v4l2_input 里获得的值,包含了设备的信号状态信息,在当前video input 被查询的时候。
##“VIDIOC_G_INPUT”的ioctl,返回一个当前video input或output的索引(index)。
可以通过“VIDIOC_S_INPUT”和“VIDIOC_S_OUTPUT”两个ioctl来选择不同的输入或输出应用程序。
#当设备具有1个或多个输入(1个或多个输出)时,驱动必须实现所有的 “输入ioctl”(输入ioctl)。
示例1-1. 当前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;//设置input中的索引
if (-1 == ioctl (fd, VIDIOC_ENUMINPUT, &input)) {//通过索引,查询枚举input,获得当前input的信息
perror ("VIDIOC_ENUMINPUT");
exit (EXIT_FAILURE);
}
printf ("Current input: %s\n", input.name);//打印获取到的名字。
示例1-2.切换到第一个video input
int index;
index = 0;//而对应的VIDIOC_G_INPUT的操作返回了index;
if (-1 == ioctl (fd, VIDIOC_S_INPUT, &index)) {//索引0对应了第一个video input;通过VIDIOC_S_INPUT根据index的值把当前设置成第一个video input
perror ("VIDIOC_S_INPUT");
exit (EXIT_FAILURE);
}
*1.5. 音频输入和输出(Audio Inputs and Outputs)
#Radio设备米有audio input或output。他们实际上是一个频道,这个频道实际上是一个audio source(音频源)。
一个TV卡的连接器轮回接受audio信号,并把信号送至声卡,那么这个TV卡上的连接器不被认为是一个audio output。
#audio和video输入输出是由关联的。假定2路符合视频输入和2路audio输入存在,那么这里可能有4个有效的联合。
video和audio连接器的关系,被定义在struct v4l2_input 和 struct v4l2_output两个结构中的audioset成员中。
audioset的每个比特表示一个索引号(index number)。
#为了知道有效的输入输出应用的number和attributes,可以通过“VIDIOC_ENUMAUDIO”和“VIDIOC_ENUMAUDOUT”对应的ioctl的功能来枚举。
struct v4l2_audio是由 “VIDIOC_ENUMAUDIO”对应的ioctl来设定的。设定之后,struct v4l2_audio中包含信号状态的信息。
#“VIDIOC_G_AUDIO”和“VIDIOC_G_AUDOUT”对应的ioctl是用来报告当前的audio输入和输出。
这两个ioctl的返回的结构体,与“VIDIOC_G_INPUT”和“VIDIOC_G_OUTPUT”对应的两个ioctl返回的结构体是不一样的,而是与“VIDIOC_ENUMAUDIO”、“VIDIOC_ENUMAUDOUT”这两个ioctl返回的结构体是一样的。
并不仅仅是返回一个index(VIDIOC_G_INPUT就只返回一个索引)。
#可以通过调用“VIDIOC_S_AUDIO”对应的ioctl来选择一个audio input和改变它的属性应用;
可以通过调用VIDIOC_S_AUDOUT”对应的ioctl来选择一个audio output(当前它没有可改变的属性)应用。
#当设备具有一个或者多个inputs/output时,驱动必须实现所有的input/output ioctls。
#当设备具有任何audio inputs或outputs,那么驱动必须设置struct v4l2_capability中的“V4L2_CAP_AUDIO”这个flag。这个结构是由VIDIOC_QUERYCAP对应的ioctl返回的。
关于v4l2_capability结构体请参考1.6.2节的内容————作者注;
示例1-3. 关于当前audio input的信息
struct v4l2_audio audio;
memset (&audio, 0, sizeof (audio));
//通过VIDIOC_G_AUDIO的ioctl查询当前的audio input,返回的信息存在audio里
if (-1 == ioctl (fd, VIDIOC_G_AUDIO, &audio)) {
perror ("VIDIOC_G_AUDIO");
exit (EXIT_FAILURE);
}
printf ("Current input: %s\n", audio.name);
&