虚拟摄像头驱动vivi的简单实现

本文详细介绍了Linux内核中vivi虚拟摄像头驱动的实现,包括驱动基本框架、数据获取过程和具体实现步骤。首先,分配并设置video_device结构体,然后注册到系统。接着,讲解了数据获取流程,涉及缓冲区的分配、查询和队列操作。最后,概述了驱动的自定义结构体、输入输出函数接口、摄像头性能查询、数据格式设置以及缓冲区管理等关键步骤。
摘要由CSDN通过智能技术生成

一、vivi摄像头驱动基本框架

  1.     分配一个video_device结构体变量
  2.     设置这个结构体变量
  3.     注册这个结构体变量

二、vivi摄像头驱动数据的获取过程

  1.     请求分配缓冲区
  2.     查询缓冲区,并为缓冲区分配空间
  3.     将缓冲区放入队列
  4.     启动摄像头
  5.     通过poll机制来对查询是否有数据,如果有数据可以通过定时器或者内核线程来唤醒它
  6.     将数据从缓冲区中取出,并将这个缓冲区从队列中删除
  7.     判断摄像头是否继续工作,如果继续工作则重复执行3、5、6步,否则结束

三、vivi摄像头驱动的简单实现步骤

1、自定义一个结构体yl_vivi_dev来表示vivi驱动的核心结构体,具体实现如下:

/* 定义一个结构体用来表示虚拟摄像头设备 */
struct yl_vivi_dev {
	struct video_device    *video_device;                  /* vivi驱动遵循V4L2框架的核心结构体 */
	struct v4l2_format 	yl_vivi_format;                /* 摄像头数据格式 */
	struct videobuf_queue 	yl_videobuf_queue;             /* 缓冲区队列 */
	spinlock_t 		yl_videobuf_queue_slock;        /* 用去缓冲区队列构建时使用的自旋锁 */
	struct list_head 	yl_videobuf_list;		/* 表示一个本地的队列,用来对缓冲区进行操作的 */
	struct timer_list 	yl_vivi_timer;                  /* 通过定时器来填充摄像头数据 */
};
static struct yl_vivi_dev *yl_vivi_dev;

2、vivi驱动模块的输入、输出函数接口定义

/* 模块入口函数 */
static int yl_vivi_init(void)
{
	int ret;

	/* 给yl_vivi_dev的结构体变量分配内存 */
	yl_vivi_dev = kzalloc(sizeof(struct yl_vivi_dev), GFP_KERNEL);
	if(!yl_vivi_dev)
	{
		return -ENOMEM;
	}

	/* 1 分配一个video_device的结构体变量 */
	yl_vivi_dev->video_device = video_device_alloc();
	if (NULL == yl_vivi_dev->video_device) 
	{
		kfree(yl_vivi_dev);
		return -ENOMEM;
	}

	/* 2 设置这个video_device结构体变量 */

	/* 2.1 给video_device结构体变量提供release函数,可以不用具体实现这个函数 */
	yl_vivi_dev->video_device->release = yl_vivi_release;

	/* 2.2 fops */
	yl_vivi_dev->video_device->fops    = &yl_vivi_fops;

	/* 2.3 ioctl_ops */
	yl_vivi_dev->video_device->ioctl_ops = &yl_vivi_ioctl_ops;
	
	/* 3 注册这个video_device结构体变量 */
	ret = video_register_device(yl_vivi_dev->video_device, VFL_TYPE_GRABBER, -1);

	return ret;
}

/* 模块出口函数 */
static void yl_vivi_exit(void)
{
	video_unregister_device(yl_vivi_dev->video_device);
	video_device_release(yl_vivi_dev->video_device);
	kfree(yl_vivi_dev);
}

    主要完成video_device结构体的分配、设置和注册工作,核心是:

/* 2.2 fops */
yl_vivi_dev->video_device->fops    = &yl_vivi_fops;

/* 2.3 ioctl_ops */
yl_vivi_dev->video_device->ioctl_ops = &yl_vivi_ioctl_ops;

    yl_vivi_fops和yl_vivi_ioctl_ops的具体定义如下所示,这两个结构体是应用程序调用驱动程序时的主要接口:

/* video_device结构体变量的file操作函数 */
static const struct v4l2_file_operations yl_vivi_fops = {
	.owner	    = THIS_MODULE,
	.open       = yl_vivi_open,
	.release    = yl_vivi_close,
	.mmap       = yl_vivi_mmap,
	.poll       = yl_vivi_poll,
	.ioctl      = video_ioctl2, /* V4L2 ioctl handler */
};

/* video_device结构体变量的ioctl操作函数 */
static const struct v4l2_ioctl_ops yl_vivi_ioctl_ops = {
    /* 查询摄像头设备的基本性能 */
    .vidioc_querycap      = yl_vivi_vidioc_querycap,

    /* 用于列举、获得、测试、设置摄像头的数据的格式 */
    .vidioc_enum_fmt_vid_cap  = yl_vivi_vidioc_enum_fmt_vid_cap,
    .vidioc_g_fmt_vid_cap     = yl_vivi_vidioc_g_fmt_vid_cap,
    .vidioc_try_fmt_vid_cap   = yl_vivi_vidioc_try_fmt_vid_cap,
    .vidioc_s_fmt_vid_cap     = yl_vivi_vidioc_s_fmt_vid_cap,

    /* 用于申请、查询、入队列、出队列的摄像头数据的缓冲区的操作 */
    .vidioc_reqbufs       = yl_vivi_vidioc_reqbufs,
    .vidioc_querybuf      = yl_vivi_vidioc_querybuf,
    .vidioc_qbuf          = yl_vivi_vidioc_qbuf,
    .vidioc_dqbuf         = yl_vivi_vidioc_dqbuf,

    /* 用于启动和关闭摄像头设备 */
    .vidioc_streamon      = yl_vivi_vidioc_streamon,
    .vidioc_streamoff     = yl_vivi_vidioc_streamoff, 
};

    下面主要工作就是设置这两个结构体变量的成员函数。

3、查询摄像头的基本性能

/* 查询摄像头设备的基本性能 */
static int yl_vivi_vidioc_querycap(struct file *file, void  *priv,
					struct v4l2_capability *cap)
{
	strcpy(cap->driver, "yl_vivi");
	strcpy(cap->card, "yl_vivi");
	cap->version = 0x0001;
	cap->capabilities =	V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
	return 0;
}

4、列举、获得、测试、设置摄像头的数据的格式

/* 列举摄像头支持的数据格式 */
static int yl_vivi_vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
					stru
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值