一、设置input源
struct v4l2_input input;
input.index = 0;
while (!ioctl(fd, VIDIOC_ENUMINPUT, &input))
{
printf("input:%s\n", input.name);
++input.index;
}
input.index = index; //设置Input的设备序号
if (ioctl(fd, VIDIOC_S_INPUT, &input) < 0)
{
printf("%s:VIDIOC_S_INPUT failed\n", __func__);
return -1;
}
进入到__video_do_ioctl,将arg强转成unsigend int *。 arg传进来的是strcut v4l2_input *类型,这里i就获得了input.index
//drivers\media\video\v4l2-ioctl.c
static long __video_do_ioctl(struct file *file,
unsigned int cmd, void *arg)
{
... ...
case VIDIOC_S_INPUT:
{
unsigned int *i = arg;
if (!ops->vidioc_s_input)
break;
dbgarg(cmd, "value=%d\n", *i);
ret = ops->vidioc_s_input(file, fh, *i);
break;
}
... ...
}
//下面补充一下struct v4l2_input的定义
struct v4l2_input {
__u32 index; /* Which input */
__u8 name[32]; /* Label */
__u32 type; /* Type of input */
__u32 audioset; /* Associated audios (bitfield) */
__u32 tuner; /* Associated tuner */
v4l2_std_id std;
__u32 status;
__u32 capabilities;
__u32 reserved[3];
};
后面我们看一下vivi.c里面实现的vidioc_s_input
//drivers\media\video\vivi.c
static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
{
struct vivi_dev *dev = video_drvdata(file);
if (i >= NUM_INPUTS)
return -EINVAL;
dev->input = i; //应用层指定的index
//根据不同的Input index vivi设置了不同的色块,下面提前将要输出的数据进行处理
precalculate_bars(dev);
precalculate_line(dev);
return 0;
}
二、设置数据格式
struct v4l2_format v4l2_fmt;
memset(&v4l2_fmt, 0, sizeof(struct v4l2_format));
v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
v4l2_fmt.fmt.pix.width = width; //图像的宽度
v4l2_fmt.fmt.pix.height = height; //图像的高度
v4l2_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; //像素格式
v4l2_fmt.fmt.pix.field = V4L2_FIELD_ANY;
if (ioctl(fd, VIDIOC_S_FMT, &v4l2_fmt) < 0)
{
printf("ERR(%s):VIDIOC_S_FMT failed\n", __func__);
return -1;
}
对应 __video_do_ioctl
//drivers\media\video\v4l2-ioctl.c
static long __video_do_ioctl(struct file *file,
unsigned int cmd, void *arg)
{
... ...
case VIDIOC_S_FMT:
{
struct v4l2_format *f = (struct v4l2_format *)arg;
/* FIXME: Should be one dump per type */
dbgarg(cmd, "type=%s\n", prt_names(f->type, v4l2_type_names));
switch (f->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
CLEAR_AFTER_FIELD(f, fmt.pix);
v4l_print_pix_fmt(vfd, &f->fmt.pix);
if (ops->vidioc_s_fmt_vid_cap) {
//vivi是走这条分支
ret = ops->vidioc_s_fmt_vid_cap(file, fh, f);
} else if (ops->vidioc_s_fmt_vid_cap_mplane) {
if (fmt_sp_to_mp(f, &f_copy))
break;
ret = ops->vidioc_s_fmt_vid_cap_mplane(file, fh,
&f_copy);
if (ret)
break;
if (f_copy.fmt.pix_mp.num_planes > 1) {
/* Drivers shouldn't adjust from 1-plane
* to more than 1-plane formats */
ret = -EBUSY;
WARN_ON(1);
break;
}
ret = fmt_mp_to_sp(&f_copy, f);
}
break;
... ...
}
... ...
}
... ...
}
vidioc_s_fmt_vid_cap函数主要就是设置采样图片的宽和高
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct vivi_dev *dev = video_drvdata(file);
struct vb2_queue *q = &dev->vb_vidq;
//判断是否支持对应格式,并重新计算图片的宽高和占用的字节数
int ret = vidioc_try_fmt_vid_cap(file, priv, f);
if (ret < 0)
return ret;
//下面判断vb2的状态是否在使用
if (vb2_is_streaming(q)) {
dprintk(dev, 1, "%s device busy\n", __func__);
return -EBUSY;
}
//将对应的格式设置到vivi_dev中去
dev->fmt = get_format(f);
dev->width = f->fmt.pix.width;
dev->height = f->fmt.pix.height;
dev->field = f->fmt.pix.field;
return 0;
}
再看一下vidioc_try_fmt_vid_cap干了啥
static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct vivi_dev *dev = video_drvdata(file);
struct vivi_fmt *fmt;
enum v4l2_field field;
fmt = get_format(f); //判断是否支持上层应用指定的V4L2_PIX_FMT_YUYV格式
if (!fmt) {
dprintk(dev, 1, "Fourcc format (0x%08x) invalid.\n",
f->fmt.pix.pixelformat);
return -EINVAL;
}
field = f->fmt.pix.field;
if (field == V4L2_FIELD_ANY) {
field = V4L2_FIELD_INTERLACED;
} else if (V4L2_FIELD_INTERLACED != field) {
dprintk(dev, 1, "Field type invalid.\n");
return -EINVAL;
}
f->fmt.pix.field = field;
//将pix.width和pix.height按照给定的数据进行对齐
v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 2,
&f->fmt.pix.height, 32, MAX_HEIGHT, 0, 0);
//计算出一行图像所占用的字节数
f->fmt.pix.bytesperline =
(f->fmt.pix.width * fmt->depth) >> 3;
//计算出一张图片所要占用的字节数
f->fmt.pix.sizeimage =
f->fmt.pix.height * f->fmt.pix.bytesperline;
return 0;
}