从vivi学习V4L2架构(五): 设置input源和支持的格式

一、设置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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值