整个v4l2的框架分为三层:

在应用层,我们可以在 /dev 目录发现 video0 类似的设备节点,上层的摄像头程序打开设备节点进行数据捕获,显示视频画面。设备节点的名字很统一,video0 video1 video2...这些设备节点在是核心层注册。

核心层 v4l2-dev.c,承上启下,对于每一个硬件相关层注册进来的设备,设置一个统一的接口 v4l2_fops ,既然是统一的接口必然不是具体的视频设备的操作函数,应用层调用 v4l2_fops 中的函数最终将调用到硬件相关层的 video_device 的 fops 。

硬件相关层,与具体的视频硬件打交道,分配、设置、注册 video_device 结构体。

static int __init videodev_init(void)
{
/* 申请设备号,留给 video 设备使用 */
dev_t dev = MKDEV(VIDEO_MAJOR, );
ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME);
/* 创建 video 类 */
ret = class_register(&video_class);
return ;
}
struct video_device
{
/* device ops */
const struct v4l2_file_operations *fops; /* sysfs */
struct device dev; /* v4l device */
struct cdev *cdev; /* character device */ /* Set either parent or v4l2_dev if your driver uses v4l2_device */
struct device *parent; /* device parent */
struct v4l2_device *v4l2_dev; /* v4l2_device parent */ /* Control handler associated with this device node. May be NULL. */
struct v4l2_ctrl_handler *ctrl_handler; /* Priority state. If NULL, then v4l2_dev->prio will be used. */
struct v4l2_prio_state *prio; /* device info */
char name[];
int vfl_type;
/* 'minor' is set to -1 if the registration failed */
int minor;
u16 num;
/* use bitops to set/clear/test flags */
unsigned long flags;
/* attribute to differentiate multiple indices on one physical device */
int index; /* V4L2 file handles */
spinlock_t fh_lock; /* Lock for all v4l2_fhs */
struct list_head fh_list; /* List of struct v4l2_fh */ int debug; /* Activates debug level*/ /* Video standard vars */
v4l2_std_id tvnorms; /* Supported tv norms */
v4l2_std_id current_norm; /* Current tvnorm */ /* callbacks */
void (*release)(struct video_device *vdev); /* ioctl callbacks */
const struct v4l2_ioctl_ops *ioctl_ops;
DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE); /* serialization lock */
DECLARE_BITMAP(disable_locking, BASE_VIDIOC_PRIVATE);
struct mutex *lock;
};
struct v4l2_device {
struct device *dev;
/* used to keep track of the registered subdevs */
struct list_head subdevs;
spinlock_t lock;
char name[V4L2_DEVICE_NAME_SIZE];
void (*notify)(struct v4l2_subdev *sd, unsigned int notification, void *arg);
struct v4l2_ctrl_handler *ctrl_handler;
struct v4l2_prio_state prio;
struct mutex ioctl_lock;
struct kref ref;
void (*release)(struct v4l2_device *v4l2_dev);
};
static inline int __must_check video_register_device(struct video_device *vdev,
int type, int nr)
{
return __video_register_device(vdev, type, nr, , vdev->fops->owner);
} int __video_register_device(struct video_device *vdev, int type, int nr,
int warn_if_nr_in_use, struct module *owner)
{
int i = ;
int ret;
int minor_offset = ;
int minor_cnt = VIDEO_NUM_DEVICES;
const char *name_base; /* A minor value of -1 marks this video device as never having been registered */
vdev->minor = -; /* 视频设备的设备节点一般为 video0 ..video 就是由此而来 */
switch (type) {
case VFL_TYPE_GRABBER:
name_base = "video";
break;
case VFL_TYPE_VBI:
name_base = "vbi";
break;
...
} vdev->vfl_type = type;
vdev->cdev = NULL; /* Part 2: find a free minor, device node number and device index. */
#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
switch (type) {
case VFL_TYPE_GRABBER:
minor_offset = ;
minor_cnt = ;
break;
...
#endif /* 寻找一个空的项,这个好像并不重要 */
mutex_lock(&videodev_lock);
nr = devnode_find(vdev, nr == - ? : nr, minor_cnt);
if (nr == minor_cnt)
nr = devnode_find(vdev, , minor_cnt);
if (nr == minor_cnt) {
printk(KERN_ERR "could not get a free device node number\n");
mutex_unlock(&videodev_lock);
return -ENFILE;
}
#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
/* 1-on-1 mapping of device node number to minor number */
i = nr;
#else
/* 在全局 video_deivce 数组中寻找一个空的项,下标+minor_offset作为设备的次设备号 */
for (i = ; i < VIDEO_NUM_DEVICES; i++)
if (video_device[i] == NULL)
break;
if (i == VIDEO_NUM_DEVICES) {
mutex_unlock(&videodev_lock);
printk(KERN_ERR "could not get a free minor\n");
return -ENFILE;
}
#endif
vdev->minor = i + minor_offset;
vdev->num = nr;
devnode_set(vdev); if (vdev->ioctl_ops)
determine_valid_ioctls(vdev); /* 注册字符设备 */
vdev->cdev = cdev_alloc();
vdev->cdev->ops = &v4l2_fops;
vdev->cdev->owner = owner;
ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), ); /* 得把device注册进内核,mdev才能自动创建设备节点,/dev 目录下的video0 等就是来自这里 */
vdev->dev.class = &video_class;
vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
if (vdev->parent)
vdev->dev.parent = vdev->parent;
dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num);
ret = device_register(&vdev->dev); vdev->dev.release = v4l2_device_release; /* Part 6: Activate this minor. The char device can now be used. */
set_bit(V4L2_FL_REGISTERED, &vdev->flags);
mutex_lock(&videodev_lock);
video_device[vdev->minor] = vdev;
mutex_unlock(&videodev_lock); return ; }
EXPORT_SYMBOL(__video_register_device);
static const struct file_operations v4l2_fops = {
.owner = THIS_MODULE,
.read = v4l2_read,
.write = v4l2_write,
.open = v4l2_open,
.get_unmapped_area = v4l2_get_unmapped_area,
.mmap = v4l2_mmap,
.unlocked_ioctl = v4l2_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = v4l2_compat_ioctl32,
#endif
.release = v4l2_release,
.poll = v4l2_poll,
.llseek = no_llseek,
};
static int v4l2_open(struct inode *inode, struct file *filp)
{
struct video_device *vdev = video_devdata(filp);
if (vdev->fops->open) { if (video_is_registered(vdev))
ret = vdev->fops->open(filp);
}
}
static ssize_t v4l2_read(struct file *filp, char __user *buf,
size_t sz, loff_t *off)
{
struct video_device *vdev = video_devdata(filp);
if (!vdev->fops->read)
return -EINVAL;
if (video_is_registered(vdev))
ret = vdev->fops->read(filp, buf, sz, off);
}
static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
{
struct video_device *vdev = video_devdata(filp);
if (!vdev->fops->mmap)
return ret;
ret = vdev->fops->mmap(filp, vm);
} static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct video_device *vdev = video_devdata(filp);
if (vdev->fops->unlocked_ioctl) {
if (video_is_registered(vdev))
ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
} else if (vdev->fops->ioctl) {
if (video_is_registered(vdev))
ret = vdev->fops->ioctl(filp, cmd, arg);
}
}

V4L2学习(三)框架分析的更多相关文章

  1. 初识V4L2(三)-------分析vivi.c 虚拟视频驱动

    1.分配video_device结构体 2.设置 3.注册  video_register_device 分析vivi.c: vivi_init( )//入口函数 vivi_create_instan ...

  2. Python学习---抽屉框架分析[点赞功能/文件上传分析]0317

    点赞功能分析 前台传递过来新闻id[new_id]和session[session内有用户ID和用户之间的信息]到后台 后台News数据库内用户和新闻是多对多的关系,查看第三张表中的内容,判读用户Id ...

  3. spring学习 三 框架的搭建

    1 导入jar包 spring启来最少要5个包,四个核心包和一个依赖的日志包 2 创建配置文件 在dynamic web project下的src目录下,创建一个spring的xml配置文件,名称可以 ...

  4. Python学习---抽屉框架分析[小评论分析]0315

    注: 此处的小评论涉及数据库操作 初级小评论代码 settings.py INSTALLED_APPS = [ ... 'app01', # 注册app ] STATICFILES_DIRS = (o ...

  5. Python学习---抽屉框架分析[ORM操作]180314

    Django ORM操作     1. 字段操作         class User(model.Model);             u=字段        用处:            1 . ...

  6. Python学习---抽屉框架分析[数据库设计分析]180313

    基本的: models.py ####################################以下都是抽屉的代码#################################### fro ...

  7. Python学习---抽屉框架分析[点赞功能分析]

    实际上就是多了一个隐藏的span标签,内容是+1,配合setInterval实现的动态效果 settings.py INSTALLED_APPS = [ ... 'app01', # 注册app ] ...

  8. v4l2框架分析

    参考:https://www.cnblogs.com/fengong/p/4424823.html    http://www.cnblogs.com/fengong/p/4424895.html 一 ...

  9. 摄像头驱动——V4L2框架分析

    一.概述 Video for Linux 2,简称V4l2,是Linux内核中关于视频设备的内核驱动框架,为上层的访问底层的视频设备提供了统一的接口. 摄像头驱动是属于字符设备驱动程序.(分析linu ...

  10. 【原创】Linux v4l2框架分析

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

随机推荐

  1. ZOJ 5638——Prime Query——————【线段树区间更新,区间查询,单点更新】

    Prime Query Time Limit: 1 Second      Memory Limit: 196608 KB You are given a simple task. Given a s ...

  2. Java并发编程的艺术,解读并发编程的优缺点

    并发编程的优缺点 使用并发的原因 多核的CPU的背景下,催生了并发编程的趋势,通过并发编程的形式可以将多核CPU的计算能力发挥到极致,性能得到提升. 在特殊的业务场景下先天的就适合于并发编程. 比如在 ...

  3. Teradata 认证系列 - 2. Teradata数据库总览

    Teradata (以下简称TD) 总览本课的学习目标 描述Teradata数据库产品的功能 知晓支持的操作系统 描述Teradata的并行架构 解释线性可扩展性 列出Teradata DBA永远不需 ...

  4. Yii2.0 高级版安装 windows

    最近在学习yii2.0 在安装高级版的时候遇到一些问题 索性解决了 下面分享一下 一.关于下载 自行百度,在Yii Framework 中文社区 下载专区下载高级应用程序模板(这边下载用电信网络不用下 ...

  5. Android 超简单的拖动按钮 悬浮按钮 吸附按钮

    第一种    第二种    第一种实现方法 xml布局 <RelativeLayout xmlns:android="http://schemas.android.com/apk/re ...

  6. Python3基础12(collections、struct、itertools、chardet等的使用)

    import struct import base64import itertoolsimport chardet from collections import namedtuple,default ...

  7. 利用ajax实现分页效果

    在网页中看到的分页效果,想一下就点击分页中的内容的时候,然后调用ajax调出对应的数据,正确的显示在相应的标签内. 1.用html实现正确的样式和结构 2.采用jquery中的ajax调出数据. 需要 ...

  8. java的图形界面初学惯用

    1.单一界面的创建 public void mainFrame() { HashMap<String, Component> views = new HashMap<String, ...

  9. libav(ffmpeg)简明教程(2)

    距离上一次教程又过去了将近一个多月,相信大家已经都将我上节课所说的东西所完全消化掉了. 这节课就来点轻松的,说说libav的命令使用吧. 注:遇到不懂的或者本文没有提到的可以用例如命令后加 --hel ...

  10. 使用bouncycastle进行DESede/DESeee/AES128/AES192/AES256的加解密

    前言 默认的jdk不支持DESeee的算法,本地化的JDK中配置有拦截规则,可以通过使用bouncycastle的jar包中的DESEngine类来进行DESeee算法的运算. DES的8字节加解密 ...