V4l2初识(七)-----------浅析app获取虚拟摄像头数据的过程
继续分析数据的获取过程:
1、请求分配的缓冲区: ioctl(4,VIDIOC_REQBUFS)
vidioc_reqbufs
2、查询和映射缓冲区
ioctl(4,VIDIOC_QUERYBUF)
mmap
3、把缓冲区放入队列
ioctl(4,VIDIOC_QBUF)
4、启动摄像头
ioctl(4,VIDIOC_STREAMON
5、用select函数查询是否有数据
//驱动程序中必定有:产生数据、唤醒进程
6、有数据后,从队列中取出缓冲区
ioctl(4,VIDIOC_DQBUF
------------------------------------------------------------------------------------------------------------------------
app: VIDIOC_REQBUFS
vidioc_reqbufs
vb2_reqbufs(&dev->vb_vidq, p)//第一个参数表示队列
注意:这个ioctl只是分配缓冲区的头部信息,真正的缓存还没有被分配,在驱动程序里有一条原则,这些资源只有在用的时候才分配。
队列是在哪个地方进行初始化的?
/*此函数主要是返回dev->p->driver_data指针,
device结构体其实是对内核中所有设备的抽象表示,所有的设备都有一个device实例与之对应
device结构体的主要用法是将其嵌入到其他的结构体中,如platform_device*/
void *dev_get_drvdata(const struct device *dev)
{
if (dev && dev->p)
return dev->p->driver_data;
return NULL;
}
static inline void *video_get_drvdata(struct video_device *vdev)
{
return dev_get_drvdata(&vdev->dev);
}
struct video_device *video_devdata(struct file *file)
{
return video_device[iminor(file->f_path.dentry->d_inode)];//根据次设备号从video_device[]数组中取出device设备
}
static inline void *video_drvdata(struct file *file)
{
return video_get_drvdata(video_devdata(file));
}
static int vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p)
{
struct vivi_dev *dev = video_drvdata(file);//根据次设备号得到dev这个结构体
return vb2_reqbufs(&dev->vb_vidq, p);//把p这个缓冲区放入dev结构体中的vb_vidq队列中
}
-------------------------------------------------------------------------------------------------------------------
app: VIDIOC_QUERYBUF//查询所分配的缓冲区
vidioc_querybuf
注意,这里只是表示缓冲区将会有多大,并不表示这个缓冲区的内存被分配
static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
struct vivi_dev *dev = video_drvdata(file);
return vb2_querybuf(&dev->vb_vidq, p);/*获得缓冲区数据格式、大小、每一行长度、高度等*/
}
mmap //在这里才分配缓存。注意在分析mmap函数时,所用的内核不是3.4.2.是根据韦老大讲解的整理的
v4l2_mmap
vivi_mmap
videobuf_mmap_mapper
_videobuf_mmap_mapper //该函数在videobuf_vmalloc.c里面
-----------------------------------------------------------------------------------------------------------
app: VIDIOC_QBUF //把缓冲区放入队列(也是根据韦老大讲解的进行整理,内核不是3.4.2)
vidioc_qbuf
videobuf_qbuf
q->ops->buf_prepare(q,buf,field)//调用驱动程序里面提供的函数做一些预处理工作
list_add_tail//把缓冲区放入队列的尾部
q->ops->buf_queue(q,buf)调用驱动程序里面提供的入队列函数
----------------------------------------------------------------------------------------------------------------
app : VIDIOC_STREAMON //启动
----------------------------------------------------------------------------------------------------------------
用select查询是否有数据(根据韦老大讲解的进行整理,内核不是3.4.2)
在驱动程序里面对应的是poll机制。
V4l2_poll
vdev->fops->poll(vivi_poll)
vivi_poll
videobuf_poll_stream
buf=list_entry(q->stream.next, struct videobuf_buffer,stream)//从队列的头部获得缓冲区
如果缓冲区里面没有数据的话,就调用poll_wait等待
poll_wait(file,&buf->done,wait)//在这里休眠
谁来产生数据,谁来唤醒它(在vivi.c中搜索done)
vivi_thread_tick
wake_up(&buf->vb.done)
唤醒进程:谁来调用vivi_thread_tick这个函数呢?
因为这里是一个虚拟的摄像头驱动程序,它会怎样产生数据呢?
如果是一个真实的摄像头的话,是硬件来产生数据的。但是在虚拟摄像头驱动里面,是用内核线程来产生数据的。
timeout = msecs_to_jiffies();
创建一个内核线程,每隔30ms就会执行一次,每次就会调用vivi_thread_tick(fh)来产生数据。在vivi_thread_tick()中会
调通过vivi_fillbuf(fh,buf)来构造数据。调完之后,又开始休眠schedule_timeout_interruptible(timeout)
---------------------------------------------------------------------------------
/*有数据后,从队列中取出缓冲区。有那么多缓冲区,app如何知道哪一个缓冲区有数据,
调用VIDIOC_DQBUF(根据韦老大讲解的进行整理,内核不是3.4.2)
app : VIDIOC_DQBUF
vidioc_dqbuf
/*在队列中获得有数据的缓冲区*/
retval = stream_next_buffer(q,&buf,nonblocking);
/*把它从队列中删掉*/
list_del(&buf->stream)
/*把缓冲区的状态返回给应用程序*/
videobuf_status(q,b,buf,q->type);
-------------------------------------------------------------------------------------------
应用程序根据VIDIOC_DQBUF所得到缓冲区的状态,知道哪一个缓冲区有数据,就去读对应的地址(该地址来自前面的mmap)
------------------------------------------------------------------------------------------
V4l2初识(七)-----------浅析app获取虚拟摄像头数据的过程的更多相关文章
- V4L2学习(五)VIVI虚拟摄像头驱动
概述 前面简单分析了内核中虚拟摄像头驱动 vivi 的框架与实现,本文参考 vivi 来写一个虚拟摄像头驱动,查询.设置视频格式相对简单,难点在于 vb2_buf 的处理过程. 数据采集流程分析 在我 ...
- 二十四、V4L2框架主要结构体分析和虚拟摄像头驱动编写
一.V4L2框架主要结构体分析 V4L2(video for linux version 2),是内核中视频设备的驱动框架,为上层访问视频设备提供统一接口. V4L2整体框架如下图: 图中主要包括两层 ...
- V4L2(二)虚拟摄像头驱动vivi深入分析【转】
转自:http://www.cnblogs.com/tureno/articles/6694463.html 转载于: http://blog.csdn.net/lizuobin2/article/d ...
- vivi虚拟摄像头驱动程序
一.vivi虚拟摄像头驱动 基于V4L2(video for linux 2)摄像头驱动程序,我们减去不需要的ioctl_fops的函数,只增加ioctl函数增加的必要的摄像头流查询等函数: #inc ...
- (二) V4L2引入(含浅析UVC)
title: V4L2引入(含浅析UVC) date: 2019/4/23 19:00:00 toc: true --- V4L2引入(含浅析UVC) 基本框架 V4L2全名是video for li ...
- FFmpeg获取DirectShow设备数据(摄像头,录屏)
这两天研究了FFmpeg获取DirectShow设备数据的方法,在此简单记录一下以作备忘.本文所述的方法主要是对应Windows平台的. 1. 列设备 ffmpeg -list_devic ...
- 【转】FFmpeg获取DirectShow设备数据(摄像头,录屏)
这两天研究了FFmpeg获取DirectShow设备数据的方法,在此简单记录一下以作备忘.本文所述的方法主要是对应Windows平台的. 1. 列设备 ffmpeg -list_devic ...
- directshow 虚拟摄像头 实例 代码解读
directshow 虚拟摄像头 实例 代码解读 本文只介绍这个源码的大致构成以及怎么修改,因为其他的我也不会啊哈哈哈,我就是用QQ调用虚拟摄像头读取我自己的视频或者图片播放给别人让别人以为这就是实时 ...
- Opencv+MFC获取摄像头数据,显示在Picture控件
分为两步:OpenCV获取摄像头数据+图像在Picture上显示 第一步:OpenCV获取摄像头数据 参考:http://www.cnblogs.com/epirus/archive/2012/06/ ...
随机推荐
- 如何在Pycharm中添加新的模块
在使用Pycharm编写程序时,我们时常需要调用某些模块,但有些模块事先是没有的,我们需要把模块添加上去. 最近在学习爬虫,写了下面几行代码: 结果出现错误 错误ModuleNotFoundError ...
- 《高性能MySQL》读后感——聚簇索引
<高性能MySQL>读后感——聚簇索引 聚簇索引并不是一种单独的索引类型,而是一种数据存储方式.比如,InnoDB的聚簇索引使用B+Tree的数据结构存储索引和数据. 当表有聚簇索引时,它 ...
- NOIP模拟赛 拓展
题目描述 Description \(φ\) 函数是数论中非常常用的函数.对于正整数 \(x\) ,\(φ(x)\) 表示不超过 \(x\) 的所有正整数与 \(x\) 互质的个数. 现在我们对它进行 ...
- AGC037C Numbers on a Circle(神奇思路)
Atcoder 全是神仙题-- 先变成能不能从 \(b\) 到 \(a\).操作变成一个数减掉旁边两个数. 考虑里面最大的且不和 \(a\) 中相等的那个数.它两边的数此时都不能操作,否则就减到非正数 ...
- MySQL实战45讲学习笔记:第三十八讲
一.本节内容 我在上一篇文章末尾留给你的问题是:两个 group by 语句都用了 order by null,为什么使用内存临时表得到的语句结果里,0 这个值在最后一行:而使用磁盘临时表得到的结果里 ...
- 5G最新套餐以及对应限速标准
原文: http://news.mydrivers.com/1/654/654529.htm 再过两天,国内的5G就要正式运营了,中国移动.联通.电信的5G预约用户亿元超过千万,三家运营商的5G套餐费 ...
- HTML连载40-盒子宽度和高度的练习、box-sizing属性
一.判断方法 1.判断是否元素宽高为200的盒子 只需要看:边框+内边距+内容宽度/内容高度的值是否等于200 2.判断是否内容宽高为100的盒子 只需要看:width和heght的值是否等于100 ...
- WPF 鼠标移动时触发图片旋转(非动画)
非动画,只是简单的触发器. 主要是针对旋转的写法. 代码 <Grid> <Image x:Name="image" Source="nifi3.gif& ...
- 状态(State)模式--设计模式
定义与特点 1.1 定义 状态模式允许一个对象在其内部状态改变的时候改变其行为.这个对象看上去就像是改变了它的类一样. 1.2 特点 状态模式优点: 封装了转换规则,并枚举可能的状态,它将所有与某个状 ...
- DAX 第七篇:分组聚合
DAX有三个用于生成分组聚合数据的函数,这三个函数有两个共同的特征:分组列和扩展列. 分组列是用于分组的列,只能来源于基础表中已存的列,分组列可以来源于同一个表,也可以来源于相关的列. 扩展列是由na ...