__video_do_ioctl
一、获取input输入源
ioctl(fd, VIDIOC_ENUMINPUT, &input); video设备可能有多个输入,也就是说一个摄像头controller可能接了几个摄像头,这里需要获取到这些摄像头的信息。
和之前的调用流程一样,APP层先会调用到video_device.cdev->ops.unlocked_ioctl也就是v4l2_ioctl,v4l2_ioctl会调用到video_device->fops.unlocked_ioctl = video_ioctl2, video_ioctl2会调用video_usercopy(file, cmd, arg, __video_do_ioctl);最后调用到__video_do_ioctl
static long __video_do_ioctl(struct file *file,
unsigned int cmd, void *arg)
{
struct video_device *vfd = video_devdata(file);
const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops;
... ...
switch (cmd) {
... ...
case VIDIOC_ENUMINPUT:
{
struct v4l2_input *p = arg;
/*
* We set the flags for CAP_PRESETS, CAP_CUSTOM_TIMINGS &
* CAP_STD here based on ioctl handler provided by the
* driver. If the driver doesn't support these
* for a specific input, it must override these flags.
*/
if (ops->vidioc_s_std) //vivi_ioctl_ops设置了vidioc_s_std所以下面将V4L2_IN_CAP_STD
p->capabilities |= V4L2_IN_CAP_STD;
if (ops->vidioc_s_dv_preset)
p->capabilities |= V4L2_IN_CAP_PRESETS;
if (ops->vidioc_s_dv_timings)
p->capabilities |= V4L2_IN_CAP_CUSTOM_TIMINGS;
if (!ops->vidioc_enum_input)
break;
ret = ops->vidioc_enum_input(file, fh, p); //下面具体看一下vidioc_enum_input()函数做了什么
if (!ret)
dbgarg(cmd, "index=%d, name=%s, type=%d, "
"audioset=%d, "
"tuner=%d, std=%08Lx, status=%d\n",
p->index, p->name, p->type, p->audioset,
p->tuner,
(unsigned long long)p->std,
p->status);
break;
}
... ...
}
......
}
/* only one input in this sample driver */
static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *inp)
{
if (inp->index >= NUM_INPUTS)
return -EINVAL;
inp->type = V4L2_INPUT_TYPE_CAMERA; //类型是camera
inp->std = V4L2_STD_525_60; //input标准类型
sprintf(inp->name, "Camera %u", inp->index); //input名字
return 0;
}
总结,上层调用VIDIOC_ENUMINPUT ioctl返回了struct v4l2_input的类型,名字,标准和能力
二、获取设备支持的格式
struct v4l2_fmtdesc fmtdesc;
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmtdesc.index = 0;
while (!ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc))
{
printf("fmt:%s\n", fmtdesc.description);
fmtdesc.index++;
}
轻车熟路,同样会调用到drivers\media\video\v4l2-ioctl.c的__video_do_ioctl函数
case VIDIOC_ENUM_FMT:
{
... ...
struct v4l2_fmtdesc *f = arg;
switch (f->type) {
case :
if (ops->vidioc_enum_fmt_vid_cap)
ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f);
break;
... ...
}
同样到了vivi.c定义的vivi_ioctl_ops中的vidioc_enum_fmt_vid_cap
static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_s_std = vidioc_s_std,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
};
vidioc_enum_fmt_vid_cap根据index为formats数组的下标获取到fourcc
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
struct vivi_fmt *fmt;
if (f->index >= ARRAY_SIZE(formats))
return -EINVAL;
fmt = &formats[f->index];
strlcpy(f->description, fmt->name, sizeof(f->description));
f->pixelformat = fmt->fourcc;
return 0;
}
static struct vivi_fmt formats[] = {
{
.name = "4:2:2, packed, YUYV",
.fourcc = V4L2_PIX_FMT_YUYV,
.depth = 16,
},
{
.name = "4:2:2, packed, UYVY",
.fourcc = V4L2_PIX_FMT_UYVY,
.depth = 16,
},
{
.name = "RGB565 (LE)",
.fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
.depth = 16,
},
{
.name = "RGB565 (BE)",
.fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
.depth = 16,
},
{
.name = "RGB555 (LE)",
.fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
.depth = 16,
},
{
.name = "RGB555 (BE)",
.fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
.depth = 16,
},
};