接嵌入式网络视频采集源程序servfox解析02
跟踪进入 init_v4l (vd)
/****************************************************************************************************
init_v4l (vd)是初始化V4L视频设备的函数,在spcav4l.c中定义:
static int
init_v4l (struct vdIn *vd)
{
int f;
int erreur = 0;
int err;
if ((vd->fd = open (vd->videodevice, O_RDWR)) == -1)//打开 视频设备
exit_fatal ("ERROR opening V4L interface");
if (ioctl (vd->fd, VIDIOCGCAP, &(vd->videocap)) == -1)
exit_fatal ("Couldn't get videodevice capability");
/*************************************************************************************************
ioctl用于向设备发控制和配置命令 ,有些命令也需要读写一些数据,但这些数据是不能用read/write读写的,称为Out-of-band数据。也就是说,read/write读写的数据是in-band数据,是I/O操作的主体,而ioctl命令传送的是控制信息,其中的数据是辅助的数据。ioctl是设备驱动程序中对设备的I/O通道进行管理的函数,所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如,在串口线上收发数据通过read/write操作,而串口的波特率、校验位、停止位通过ioctl设置,A/D转换的结果通过read读取,而A/D转换的精度和工作频率通过ioctl设置。
ioctl函数是文件结构中的一个属性分量,就是说如果你的驱动程序提供了对ioctl的支持,用户就可以在用户程序中使用ioctl函数控制设备的I/O通道。
如果不用ioctl的话,也可以实现对设备I/O通道的控制,但那就是蛮拧了。例如,我们可以在驱动程序中实现write的时候检查一下是否有特殊约定的数据流通过,如果有的话,那么后面就跟着控制命令(一般在socket编程中常常这样做)。但是如果这样做的话,会导致代码分工不明,程序结构混乱,程序员自己也会头昏眼花的。
所以,我们就使用ioctl来实现控制的功能 。要记住,用户程序所作的只是通过命令码告诉驱动程序它想做什么,至于怎么解释这些命令和怎么实现这些命令,这都是驱动程序要做的事情。
int ioctl(int fd, ind cmd, …);
其中fd就是用户程序打开设备时使用open函数返回的文件标示符,cmd就是用户程序对设备的控制命令,至于后面的省略号,那是一些补充参数,一般最多一个,有或没有是和cmd的意义相关的。
调用函数ioctl (vd->fd, VIDIOCGCAP, &(vd->videocap))成功后可读取vd->capability各分量 , 读video_capability 中信息包括设备名称,支持最大最小分辨率,信号源信息等。
video_capability是Video4linux支持的数据结构, 在前面定义:
struct vdIn {
int fd; //设备 描述符, 文件描述符
char *videodevice ; //设备, 视频捕捉接口文件
struct video_mmap vmmap;
struct video_capability videocap; // 包含设备的基本信息(设备名称、支持的最大最小分辨率、信号源 .....................................
}
.
video_capability 包含设备的基本信息(设备名称、支持的最大最小分辨率、信号源信息等),包含的分量:
•name[32] //设备名称
•maxwidth ,maxheight,minwidth,minheight
•Channels //信号源个数
•type //是否能capture,彩色还是黑白,是否能裁剪等等。值如VID_TYPE_CAPTURE等
************ ***************************************************************************************** /
if(debug) printf ("Camera found: %s /n", vd->videocap.name);
snprintf (vd->cameraname, 32, "%s", vd->videocap.name);
/*********************************************************************************************
我们通过在 Video4Linux视频设备数据结构中:
struct vdIn {
int fd; //设备 描述符, 文件描述符
char *videodevice ; //设备, 视频捕捉接口文件
struct video_mmap vmmap;
struct video_capability videocap;
............................................
char *cameraname; //设备名称
}
定义 struct video_capability videocap这个结构体,通过上面的 ioctl (vd->fd, VIDIOCGCAP, &(vd->videocap))获得视频采集设备的名称后传给 vd->cameraname。
*********************************************************************************************/
erreur = GetVideoPict (vd);
/*********************************************************************************************
GetVideoPict()也在spcav4l.c中定义:
static int
GetVideoPict (struct vdIn *vd)
{
if (ioctl (vd->fd, VIDIOCGPICT, &vd->videopict) < 0)
exit_fatal ("Couldnt get videopict params with VIDIOCGPICT");
-------------------------------------------------------------
跟 ioctl (vd->fd, VIDIOCGCAP, &(vd->videocap))类似, ioctl (vd->fd, VIDIOCGPICT, &vd->videopict) 获取摄象头缓冲区中video_picture 中各 分量的值。
vd->videopict在下面定义:
struct vdIn {
int fd; //设备 描述符, 文件描述符
char *videodevice ; //设备, 视频捕捉接口文件
struct video_mmap vmmap;
struct video_capability videocap; // 包含设备的基本信息(设备名称、支持的最大最小分辨率、信 号源信息等)
int mmapsize;
struct video_mbuf videombuf; //映射的帧信息,实际是映射到摄像头存储缓冲区的帧信息,包括帧 的大小(size),最多支持的帧数(frames) 每帧相对基址的偏移 (offset)
struct video_picture videopict; //采集图像的各种属性
struct video_window videowin;
struct video_channel videochan;
...................................................................................
}
我们来看看 struct video_picture videopict这个结构体:
struct video_picture
{
__u16 brightness;
__u16 hue;
__u16 colour;
__u16 contrast;
__u16 whiteness; /* Black and white only */
__u16 depth; /* Capture depth */
__u16 palette; /* Palette in use */
}
video_picture 设备采集的图象的各种属性
•brightness 0~65535 亮度
•hue
•colour
•contrast 对比度
•whiteness
•depth // 24 色深
•palette //VIDEO_PALETTE_RGB24 调色板
picture 结构包括了亮度,对比度,色深,调色板等等信息
-------------------------------------------------------------
if(debug) printf ("VIDIOCGPICT brightnes=%d hue=%d color=%d contrast=%d whiteness=%d"
"depth=%d palette=%d/n", vd->videopict.brightness,
vd->videopict.hue, vd->videopict.colour, vd->videopict.contrast,
vd->videopict.whiteness, vd->videopict.depth,
vd->videopict.palette);
return 0;
}
这个函数是为了获得 摄象头 采集到的图象 缓冲区中video_picture 中各分量的值
如果要对 对采集图象的各种属性进行设置,可分为两步进行, 首先获取摄象头缓冲区中video_picture中信息调用函数ioctl(vd->fd, VIDIOCGPICT, &(vd->picture));然后改变video_picture中分量的值, 调用 ioctl (vd->fd, VIDIOCSPICT, &vd->videopict) 为vd->videopict分量赋新值。
*********************************************************************************************/
if (ioctl (vd->fd, VIDIOCGCHAN, &vd->videochan) == -1)
{
if(debug) printf ("Hmm did not support Video_channel/n");
vd->cameratype = UNOW;
}
/*********************************************************************************************
同样, ioctl (vd->fd, VIDIOCGCHAN, &vd->videochan)可以获得 各个信号源的属性的信息
要 上面的 struct vdIn中定义的 struct video_channel videochan
video_channel 关于各个信号源的属性
Channel //信号源的编号
name
tuners
Type VIDEO_TYPE_TV | IDEO_TYPE_CAMERA
Norm制式
struct video_channel在 v4l API 中定义:
struct video_channel
{
int channel;
char name[32];
int tuners;
__u32 flags;
#define VIDEO_VC_TUNER 1 /* Channel has a tuner */
#define VIDEO_VC_AUDIO 2 /* Channel has audio */
__u16 type;
# define VIDEO_TYPE_TV 1
#define VIDEO_TYPE_CAMERA 2
__u16 norm; /* Norm set by channel */
};
成员channel代表输入源,通常,0: television 1:composite1 2:s-video
name 表示该输入源的名称。
norm 表示制式,通常,0:pal 1:ntsc 2:secam 3:auto
在linux下,在 /usr/include/linux /videodev.h中有详细定义。
vd->cameratype:在
struct vdIn {
.................................
int cameratype ; // 是否能capture,彩色还是黑白,是否 能裁剪等等
char *cameraname; //设备名称
char bridge[9];
........................................
}
中定义。
**********************************************************************************************/
else
{
if (vd->videochan.name){
if(debug) printf ("Bridge found: %s /n", vd->videochan.name);
snprintf (vd->bridge, 9, "%s", vd->videochan.name);
vd->cameratype = GetStreamId (vd->bridge);
}
/*********************************************************************************************
进入:GetStreamId ()函数定义在spcav4l.c中:
static int
GetStreamId (const char *BridgeName)
{
int i = -1;
int match = -1;
/* return Stream_id otherwhise -1 */
if ((match = isSpcaChip (BridgeName)) < 0)
{
if(debug) printf ("Not an Spca5xx Camera !!/n");
return match;
}
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
isSpcaChip也定义在spcav4l.c中:在 GetStreamId()的上面。
static int
isSpcaChip (const char *BridgeName)
{
int i = -1;
int find = -1;
int size = 0;
/* Spca506 return more with channel video, cut it */
/* return Bridge otherwhise -1 */
for (i = 0; i < MAX_BRIDGE -1; i++)
{
size = strlen (Blist[i].name) ;
===========================================
MAX_BRIDGE在spcav4l.h中定义,是一个枚举成员
static struct bridge_list Blist[]={
Blist[]数组在spcav4l.c前面定义:
static struct bridge_list Blist[]={
{BRIDGE_SPCA505,"SPCA505"},
{BRIDGE_SPCA506,"SPCA506"},
{BRIDGE_SPCA501,"SPCA501"},
{BRIDGE_SPCA508,"SPCA508"},
{BRIDGE_SPCA504,"SPCA504"},
{BRIDGE_SPCA500,"SPCA500"},
{BRIDGE_SPCA504B,"SPCA504B"},
{BRIDGE_SPCA533,"SPCA533"},
{BRIDGE_SPCA504C,"SPCA504C"},
{BRIDGE_SPCA561,"SPCA561"},
{BRIDGE_SPCA536,"SPCA536"},
{BRIDGE_SONIX,"SN9C102"},
{BRIDGE_ZR364XX,"ZR364XX"},
{BRIDGE_ZC3XX,"ZC301-2"},
{BRIDGE_CX11646,"CX11646"},
{BRIDGE_TV8532,"TV8532"},
{BRIDGE_ETOMS,"ET61XX51"},
{BRIDGE_SN9CXXX,"SN9CXXX"},
{BRIDGE_MR97311,"MR97311"},
{BRIDGE_UNKNOW,"UNKNOW"},
{-1,NULL}
};
static struct bridge_list结构体
===========================================
if(debug) printf ("is_spca %s size %d /n",Blist[i].name,size);
if (strncmp (BridgeName, Blist[i].name, size) == 0)
{
find = i;
break;
}
}
return find;
}
函数原型:extern int strcmp(char *str1,char * str2,int n)
参数说明:str1为第一个要比较的字符串,str2为第二个要比较的字符串,n为指定的str1与str2的比较的 字符数。
所在库名:#include <string.h>
函数功能:比较字符串str1和str2的前n个字符。
返回说明:返回整数值:当str1<str2时,返回值<0; 当str1=str2时,返回值=0; 当str1>str2时,返回值>0。
…………………………………………………………………………………………………
switch (match)
{
case BRIDGE_SPCA505:
case BRIDGE_SPCA506:
i = YYUV;
break;
case BRIDGE_SPCA501:
i = YUYV;
break;
case BRIDGE_SPCA508:
i = YUVY;
break;
case BRIDGE_SPCA536:
case BRIDGE_SPCA504:
case BRIDGE_SPCA500:
case BRIDGE_SPCA504B:
case BRIDGE_SPCA533:
case BRIDGE_SPCA504C:
case BRIDGE_ZR364XX:
case BRIDGE_ZC3XX:
case BRIDGE_CX11646:
case BRIDGE_SN9CXXX:
case BRIDGE_MR97311:
i = JPEG;
break;
case BRIDGE_ETOMS:
case BRIDGE_SONIX:
case BRIDGE_SPCA561:
case BRIDGE_TV8532:
i = GBRG;
break;
default:
i = UNOW; // -1;
if(debug) printf ("Unable to find a StreamId !!/n");
break;
}
return i;
}
返回的是视频图像信号的格式。
现在退出GetStreamId(),回到init_v4l (struct vdIn *vd)中:
*********************************************************************************************/
回到init_v4l (struct vdIn *vd)中, 请看 嵌入式网络视频采集源程序servfox解析04