继续分析数据的获取过程:  

  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获取虚拟摄像头数据的过程的更多相关文章

  1. V4L2学习(五)VIVI虚拟摄像头驱动

    概述 前面简单分析了内核中虚拟摄像头驱动 vivi 的框架与实现,本文参考 vivi 来写一个虚拟摄像头驱动,查询.设置视频格式相对简单,难点在于 vb2_buf 的处理过程. 数据采集流程分析 在我 ...

  2. 二十四、V4L2框架主要结构体分析和虚拟摄像头驱动编写

    一.V4L2框架主要结构体分析 V4L2(video for linux version 2),是内核中视频设备的驱动框架,为上层访问视频设备提供统一接口. V4L2整体框架如下图: 图中主要包括两层 ...

  3. V4L2(二)虚拟摄像头驱动vivi深入分析【转】

    转自:http://www.cnblogs.com/tureno/articles/6694463.html 转载于: http://blog.csdn.net/lizuobin2/article/d ...

  4. vivi虚拟摄像头驱动程序

    一.vivi虚拟摄像头驱动 基于V4L2(video for linux 2)摄像头驱动程序,我们减去不需要的ioctl_fops的函数,只增加ioctl函数增加的必要的摄像头流查询等函数: #inc ...

  5. (二) V4L2引入(含浅析UVC)

    title: V4L2引入(含浅析UVC) date: 2019/4/23 19:00:00 toc: true --- V4L2引入(含浅析UVC) 基本框架 V4L2全名是video for li ...

  6. FFmpeg获取DirectShow设备数据(摄像头,录屏)

    这两天研究了FFmpeg获取DirectShow设备数据的方法,在此简单记录一下以作备忘.本文所述的方法主要是对应Windows平台的. 1.       列设备 ffmpeg -list_devic ...

  7. 【转】FFmpeg获取DirectShow设备数据(摄像头,录屏)

    这两天研究了FFmpeg获取DirectShow设备数据的方法,在此简单记录一下以作备忘.本文所述的方法主要是对应Windows平台的. 1.       列设备 ffmpeg -list_devic ...

  8. directshow 虚拟摄像头 实例 代码解读

    directshow 虚拟摄像头 实例 代码解读 本文只介绍这个源码的大致构成以及怎么修改,因为其他的我也不会啊哈哈哈,我就是用QQ调用虚拟摄像头读取我自己的视频或者图片播放给别人让别人以为这就是实时 ...

  9. Opencv+MFC获取摄像头数据,显示在Picture控件

    分为两步:OpenCV获取摄像头数据+图像在Picture上显示 第一步:OpenCV获取摄像头数据 参考:http://www.cnblogs.com/epirus/archive/2012/06/ ...

随机推荐

  1. c# WF 第5节 窗体的控件

    本节内容: 1:控件在哪里 2:控件怎么添加 3:窗口的显示与隐藏 4:实例单击窗体,出现另一个窗体 1:控件在哪里 视图 --> 工具箱 2:控件怎么添加 第一种:从工具箱直接拉 第二种:在代 ...

  2. Tensorflow之MNIST手写数字识别:分类问题(1)

    一.MNIST数据集读取 one hot 独热编码独热编码是一种稀疏向量,其中:一个向量设为1,其他元素均设为0.独热编码常用于表示拥有有限个可能值的字符串或标识符优点:   1.将离散特征的取值扩展 ...

  3. Python企业面试题(系列目录)

    本系列计划把Python面试中出现频率比较高知识点整理出来,以便各位童鞋复习和练习: [第1题] Python内存管理以及垃圾回收机制 [第2题] 链表的逆置 [第3题] 两个队列创建一个栈 [第4题 ...

  4. 浅谈js的事件冒泡和事件捕获

    本文地址:https://www.cnblogs.com/christineqing/p/7607113.html 前言:    这篇文章起源于上次工作上的原因,在事件上出的bug,所以就抽空写出一篇 ...

  5. zz《可伸缩服务架构 框架与中间件》综合

    第1章 如何设计一款永不重复的高性能分布式发号器 1. 为什么不直接采用UUID? 虽然UUID能够保证唯一性,但无法满足业务系统需要的很多其他特性,比如时间粗略有序性.可反解和可制造性(说人话,就是 ...

  6. 利用OpenCV实现图像拼接Stitching模块讲解

    https://zhuanlan.zhihu.com/p/71777362 1.1 图像拼接基本步骤 图像拼接的完整流程如上所示,首先对输入图像提取鲁棒的特征点,并根据特征描述子完成特征点的匹配,然后 ...

  7. Docker 简单发布dotnet core项目 图文版

    原文:https://www.cnblogs.com/chuankang/p/9474591.html docker发布dotnet core简单流程 需要结合这个版本看哈 地址:https://ww ...

  8. Vue indent eslint缩进webstorm冲突解决

    参考教程 官方回复 ESlint设置 rules: { 'no-multiple-empty-lines': [1, {max: 3}], // 控制允许的最多的空行数量 'vue/script-in ...

  9. 【ECNU619】白网吧(差分)

    点此看题面 大致题意: 给你\(n\)个区间,求最多有多少个区间重叠,以及平均每个点被多少个区间覆盖. 第一个询问 这个应该可以直接离散化+差分,即我们先把每个区间右端点加\(1\),然后对于一个离散 ...

  10. NORDIC超低功耗蓝牙4.0 NRF51822QFAA和NRF51802QFAA

    51822-QFAA和51802-QFAA在FLASH RAM的容量没有差别, 两者都是出自NORDIC原厂,: 区别在于: 1.接收灵敏度 51802是-91dBm;51822是-93dBm,这个差 ...