看韦东山视频第三期摄像头驱动中构造了自己的vivi驱动,但是使用的videoBuf结构体,新的版本用的是vb2_buffer结构,我机器上(ubuntu12.04)使用的内核是linux3.2,看了看改动还是挺大的,自己看代码自己理解了下:
首先是韦东山老师总结的摄像头驱动的架构如下
摄像头驱动程序必需的11个ioctl:
// 表示它是一个摄像头设备
.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_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
分析数据的获取过程:
1. 请求分配缓冲区: ioctl(4, VIDIOC_REQBUFS // 请求系统分配缓冲区
2. 查询映射缓冲区: ioctl(4, VIDIOC_QUERYBUF // 查询所分配的缓冲区
3. 把缓冲区放入队列: ioctl(4, VIDIOC_QBUF // 把缓冲区放入队列
4. 启动摄像头 ioctl(4, VIDIOC_STREAMON
5. 用select查询是否有数据
6. 有数据后从队列里取出缓冲区 ioctl(4, VIDIOC_DQBUF
7. 应用程序根据VIDIOC_DQBUF所得到缓冲区状态,知道是哪一个缓冲区有数据 就去读对应的地址(该地址来自前面的mmap)
对于架构都是一样的,有关于VB2_buffer 的主要是数据的获取过程,根据韦东山老师的视频中分析步骤分析如下:
1,首先是创建并初始化一个vb2_queue结构体 ,
static struct vb2_queue Myvivi_vb2_queue;
struct vb2_queue *q = &Myvivi_vb2_queue;
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // 类型
q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; // 该队列支持的模式
q->drv_priv = dev; // 自定义模式
q->buf_struct_size = sizeof(struct vivi_buffer); // 将vb2_buffer结构体封装到我们自己的buffer中,此为我们自己的buffer的size
q->ops = &vivi_video_qops;
q->mem_ops = &vb2_vmalloc_memops; //
vb2_queue_init(q);
其中vivi_video_qops 是 队列的操作函数,以后的REQBUFS 等请求会调用到此中的函数,其结构如下
static struct vb2_ops vivi_video_qops = {
.queue_setup = queue_setup, // 必须有,vb2_queue_init中会判断
.buf_init = buffer_init,
.buf_prepare = buffer_prepare,
.buf_finish = buffer_finish,
.buf_cleanup = buffer_cleanup,
.buf_queue = buffer_queue, // 必须有,vb2_queue_init中会判断
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
.wait_prepare = vivi_unlock,
.wait_finish = vivi_lock,
};
其中vb2_vmalloc_memops用于有关此队列中mem分配问题,其中的函数一般不需要我们自己写,使用默认
const struct vb2_mem_ops vb2_vmalloc_memops = {
.alloc = vb2_vmalloc_alloc,
.put = vb2_vmalloc_put,
.vaddr = vb2_vmalloc_vaddr,
.mmap = vb2_vmalloc_mmap,
.num_users = vb2_vmalloc_num_users,
};
2,初始化完成后,调用VIDIOC_REQBUFS 请求系统分配缓冲区,该函数的调用过程如下
vb2_reqbufs ===》
q->ops->queue_setup此函数允许我们的驱动函数自定义分配空间的大小
__vb2_queue_alloc 分配vivi_buffer结构体的空间(缓存区头部信息), 如果使用的是V4L2_MEMORY_MMAP类型则 调用==>__vb2_buf_mem_alloc ==> q->mem_ops->alloc 即vb2_vmalloc_alloc 分配空间,将分配的空间指向vb2_buffer->planes[0].mem_priv ,该指针保存着分配到的空间,该指针指向vb2_vmalloc_buf结构体
韦东山老师视频中讲的video_buf中,讲到在这不真正的分配空间,但是在vb2中此时却已经分配了空间,这是我的理解
3,查询映射缓冲区 VIDIOC_QUERYBUF , 返回实际上分配到的buffer,
查询分配好的缓存区,返回v4l2_buffer结构,设置vb->state
4,使用mmap
vb2_mmap ==》q->mem_ops->mmap 即 vb2_vmalloc_mmap 用于映射,将上面分配好的vb2_buffer->planes[0].mem_priv指向的空间重映射到mmap参数中的用户空间
5,把缓冲区放入队列: VIDIOC_QBUF
vb2_qbuf 将 list_add_tail(&vb->queued_entry, &q->queued_list); 将vb2_buffer 放入队列q的queued_list中
设置vb->state = VB2_BUF_STATE_PREPARED;
6, 启动摄像头 VIDIOC_STREAMON
vb2_streamon
q->streaming = 1;
// 如果 q->queued_list 中部位空,即有qbuf没有被处理 调用__enqueue_in_driver ()
7, 用select查询是否有数据 会调用poll函数
vb2_poll 等待 q->done_list 中有数据,
8, 怎样往 q->done_list 中添加数据呢 ?
每次调用qbuf 和 vidioc_streamon 时候都会查询,如果这两个条件都成立,则调用q->ops->buf_queue 将 核心中的vb2_buffer调如我们写的驱动中,放入一个列表, 在vivi中 周期性的调用函数向这个列表中的vb缓冲区中添加数据 即 向vb2_buffer->planes中添加数据 ,然后后调用
vb2_buffer_done(&vb, VB2_BUF_STATE_DONE); ==》 list_add_tail(&vb->done_entry, &q->done_list); 将vivi驱动中的vb2 放入 q->done_list中 ,然后设置vb->state = VB2_BUF_STATE_DONE;
最后wake_up(&q->done_wq); 唤醒poll中休眠的进程。
9,调用VIDIOC_DQBUF, 从队列里取出缓冲区
vb2_dqbuf ==> __vb2_get_done_vb 将q->done_list 中的vb2_buffer中提出来,然后 将vb2_buffer中的v4l2_buffer信息返回,并将其从q->done_list 中删除
10,应用程序将数据取出来(mmap的空间)
总结:
结构体如下
struct vb2_buffer {
struct v4l2_buffer v4l2_buf; // 里面有该vb2中数据的信息
struct v4l2_plane v4l2_planes[VIDEO_MAX_PLANES];
struct vb2_queue *vb2_queue;
unsigned int num_planes;
/* Private: internal use only */
enum vb2_buffer_state state;
struct list_head queued_entry;
struct list_head done_entry;
struct vb2_plane planes[VIDEO_MAX_PLANES]; // 存放实际数据的结构
};
struct vb2_queue {
enum v4l2_buf_type type;
unsigned int io_modes;
unsigned int io_flags;
const struct vb2_ops *ops;
const struct vb2_mem_ops *mem_ops;
void *drv_priv;
unsigned int buf_struct_size;
/* private: internal use only */
enum v4l2_memory memory;
struct vb2_buffer *bufs[VIDEO_MAX_FRAME];
unsigned int num_buffers;
struct list_head queued_list;
atomic_t queued_count;
struct list_head done_list;
spinlock_t done_lock;
wait_queue_head_t done_wq;
void *alloc_ctx[VIDEO_MAX_PLANES];
unsigned int plane_sizes[VIDEO_MAX_PLANES];
unsigned int streaming:1;
struct vb2_fileio_data *fileio;
};
在vb2中细化了锁,并且将核心部分封装,使我们更容易使用。
与vb中有冲突的地方如下
1,结构中红色部分都为自己的数据,一般对于我们的驱动程序来说不要使用,因此使用vb2_buffer时候不能(也不需要)直接指定vb->state 的内容。 比如说通知数据完成只需要调用 vb2_buffer_done(&vb2, VB2_BUF_STATE_DONE); 即可,
2,对于vb2_buffer,没用供我们使用的list,因此如果要将vb可以放入list head,需要我们自己添加list ,例如
struct vivi_buffer {
/* common v4l buffer stuff -- must be first */
struct vb2_buffer vb;
struct list_head list;
};
使用vb2,总结如下
1,调用vb2_queue_init 初始化队列 q 。
2,调用reqbuf 时候会根据请求(v4l2_requestbuffers)分配vb2结构,并且加入到q->buf中
3,调用querybuf时候,根据信息(v4l2_buffer)返回q->buf中对应的vb2_buffer的信息(v4l2_buffer)
4,mmap上面信息对应的 vb空间到用户空间
5,调用qbuf 时,将对应的vb2_buffer ( vivi_bufer->list )添加到 q->queued_list 队列中
6,使用select 调用poll 休眠等待 q->done_list 有数据
7, 调用qbuf 和 vidioc_streamon 时候都会查询,如果这两个条件都成立,则调用q->ops->buf_queue 将 核心中的vb2_buffer调如我们写的驱动中,放入一个列表,然后等待(上面的poll过程休眠)我们的驱动程序将数据放入该vb2_buffer
8, 数据存放完成后 调用vb2_buffer_done函数,即将上面有数据的vb2_buffer放入q->done_list中,然后唤醒上面poll休眠的进程
9, poll唤醒后会调用dqbuf将q->done_list 中的vb2_buffer提出来后,将此vb2的信息(v4l2_buffer)返回
10, 应用程序得到buffer信息后,就去对应的mmap后的用户空间中读数据。
以上为这次根据韦东山视频步骤对vivi程序的分析,如有错误,忘指出
- YYCache 源码分析(一)
iOS 开发中总会用到各种缓存,YYCache或许是你最好的选择.性能上有优势,用法也很简单.作者ibireme曾经对比过同类轮子:http://blog.ibireme.com/2015/10/26 ...
- Spark大型项目实战:电商用户行为分析大数据平台
本项目主要讲解了一套应用于互联网电商企业中,使用Java.Spark等技术开发的大数据统计分析平台,对电商网站的各种用户行为(访问行为.页面跳转行为.购物行为.广告点击行为等)进行复杂的分析.用统计分 ...
- Android应用Activity、Dialog、PopWindow、Toast窗体加入机制及源代码分析
[工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处.尊重劳动成果] 1 背景 之所以写这一篇博客的原因是由于之前有写过一篇<Android应用setCont ...
- Linux内核[CVE-2016-5195] (dirty COW)原理分析
[原创]Linux内核[CVE-2016-5195] (dirty COW)原理分析-二进制漏洞-看雪论坛-安全社区|安全招聘|bbs.pediy.com https://bbs.pediy.com/ ...
- 从jquery源码中看类型判断和数组的一些操作
在深入看jquery源码中,大家会发现源码写的相当巧妙.那我今天也通过几个源码中用到的技巧来抛砖引玉,希望大家能共同研究源码之精华,不要囫囵吞枣. 1.将类数组转化成数组 我想大家首先想到的方法是fo ...
- CVE: 2014-6271、CVE: 2014-7169 Bash Specially-crafted Environment Variables Code Injection Vulnerability Analysis
目录 . 漏洞的起因 . 漏洞原理分析 . 漏洞的影响范围 . 漏洞的利用场景 . 漏洞的POC.测试方法 . 漏洞的修复Patch情况 . 如何避免此类漏洞继续出现 1. 漏洞的起因 为了理解这个漏 ...
- Android Context 是什么?
andorid 开发(42) 版权声明:本文为博主原创文章,未经博主允许不得转载. [转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树] PS ...
- 传智播客C语言视频第二季(第一季基础上增加诸多C语言案例讲解,有效下载期为10.5-10.10关闭)
卷 backup 的文件夹 PATH 列表卷序列号为 00000025 D4A8:14B0J:.│ 1.txt│ c语言经典案例效果图示.doc│ ├─1传智播客_尹成_C语言从菜鸟到高手_第一 ...
- STM32F072B-DISCO 深入研究 中断系统
STM32F072B-DISCO 是我认为性价比最高的一款CPU的demo系统,以前一直在用PIC的CPU但最近几年ST异军突起,几次课题查找芯片无一例外都是ST,像USB,CAN,ZIGBEE等,S ...
随机推荐
- js闭包中注意文字总结
//闭包注意的点 //闭包中使用外部变量不是复制而是引用 //闭包可以节省传递参数问题 //在循环中使用闭包
- DG应用日志相关操作
应用archive log: recover managed standby database disconnect; 应用redo logfile: recover managed stan ...
- 修改url中某个参数
function changeURLArg(url,arg,arg_val){ var pattern=arg+'=([^&]*)'; var replaceText=arg+'='+arg_ ...
- pstree---树状图的方式展现进程
pstree命令以树状图的方式展现进程之间的派生关系,显示效果比较直观. 语法 pstree(选项) 选项 -a:显示每个程序的完整指令,包含路径,参数或是常驻服务的标示: -c:不使用精简标示法: ...
- metadata 和 routing
虽然在刚开始源码概述时把代码分为分布式和数据两部分,但是它们的界限并不明显.之前这几篇可以说是这两部分的衔接.我们在快速接近数据(index)部分.本篇分析一下之前分析cluster遗留下的问题:Me ...
- 5.Node.js 安装配置
转自:http://www.runoob.com/nodejs/nodejs-tutorial.html Node.js安装包及源码下载地址为:https://nodejs.org/en/downlo ...
- SPOJ 3899. Finding Fractions 连分数
连分数乱搞,我反正是一眼没看出结果 某巨巨把这题讲解的比较详细 : http://blog.csdn.net/gogdizzy/article/details/8727386 令k = [a/b] 然 ...
- 洛谷 P1689 方程求解
P1689 方程求解 题目描述 给一个方程,形如X+Y=Z或X-Y=Z.给出了其中两个未知数,请求出第三个数.未知数用‘?’表示,等式中也许会出现一些多余的空格. 输入输出格式 输入格式: 一行,方程 ...
- [置顶]
WebService学习总结(3)——使用java JDK开发WebService
一.WebService的开发手段 使用Java开发WebService时可以使用以下两种开发手段 1. 使用JDK开发(1.6及以上版本) 2.使用CXF框架开发(工作中) 二.使用JDK开发Web ...
- WPF 支持分组互斥的 RadioButton 式单选菜单
扩展 MenuItem 为同组互斥的 RadioMenuItem,并且将对勾符号修改为圆点. http://stackoverflow.com/a/35692688/5972372 这个问题下还有其他 ...