关于v4l2,一些注意de地方

转载 2012年03月26日 15:38:24

首先来看 Read/Write ,如果 VIDIOC_QUERYCAP 调用返回的 v4l2_capability 参数中, V4L2_CAP_READWRITE 被设置成真了的话,就说明支持 Read/Write I/O 。这是最简单最原始的方法,它需要进行数据 的拷贝 ( 而不是像memory map 那样只需要进行指针的交换 ) ,而且不会交换元数据 ( 比如说帧计数器和时间戳之类的可用于识别帧丢失和进行帧同步 ) ,虽然它是最原始的方法,但因为其简单,所以对于简单的应用 程序比如只需要 capture静态图像是很有用的 。

如果使用 Read/Write 方法支持的话,必须同时支持另外两个函数 select()  poll() ,这两个函数用来进行 I/0 的多路复用。

对于 streaming 它有两种方式, driver 对两种方式的支持要使用 VIDIOC_REQBUFS 来确定:

int ioctl(int fd, int request, struct v4l2_requestbuffers *argp);

对于 memory mapped 方式, Memory mapped buffers 是通过 VIDIOC_REQBUFS  device memory 中申请的,而且必须在 map 进应用程序虚拟地址空间 之前就申请好。而对于 User pointers  User buffers 是在应用程序自己开辟的,只是通过 VIDIOC_REQBUFS 将驱动转化到 user pointer  I/O 模式下。这两种方式都不会拷贝数据,而只是 buffer 指针的交互。

首先来看一下 v4l2_requestbuffers 这个数据结构:

__u32 count

// 要申请的 buffer 的数量,只有当 memory 被设置成 V4L2_MEMORY_MMAP 的时候才会设置这个参数

enum v4l2_buf_type type

enum v4l2_memory memory

// 要么是 V4L2_MEMORY_MMAP ,要么是 V4L2_MEMORY_USERPTR

对于 memory mapped 模式,要在 device memory 下申请 buffer ,应用程序必须初始化上面的 3 个参数,驱动最后返回的 buffer 的个数可能等于 count ,也可能少于或者多于 count ,少于可能是因为内存不足,多于则可能是驱动为更好地完成相应功能增加的 buffer 。如果 driver 不支持 memory mapped 调用这个 ioctl 就会返回 EINVAL

因为 memory map 模式下分配的是实实在在的物理内存,不是虚拟内存,所以使用完以后一定要使用 munmap()释放。

应用程序可以重新调用 VIDICO_REQBUFS 来改变 buffer 的个数,但前提是必须先释放已经 mapped  buffer ,可以先 munmap ,然后设置参数 count  0 来释放所有的 buffer 

对于 User pointer I/O ,应用程序只需设置上面的 type  memory 类型就可以了。

申请好 buffer 后在进行 memory mapped 之前,首先要使用 VIDIOC_QUERYBUF 来获得分配的 buffer 信息,以传给函数 mmap() 来进行 map 

int ioctl(int fd, int request, struct v4l2_buffer *argp);

VIDIOC_QUERYBUF  memory mapped 这种模式下使用的方法,在 User pointer 模式下不需要使用这个函数,在调用之前应用程序需要设定 v4l2_buffer 中的两个参数,一个是 buffer 类型,另外一个是 index number( 有效值从0 到申请的 buffer 数目减 1) ,调用这个 ioctl 会将相应 buffer 中的 flag  V4L2_BUF_FLAG_MAPPED, V4L2_BUF_FLAG_QUEUED  V4L2_BUF_FLAG_DONE 设置为有效。下面我们来仔细看看 v4l2_buffer 这个数据结构:

__u32 index

// 应用程序来设定,仅仅用来申明是哪个 buffer

enum v4l2_buf_type type

__u32 bytesused

//buffer 中已经使用的 byte 数,如果是 input stream  driver 来设定,相反则由应用程序来设定

__u32 flags

// 定义了 buffer 的一些标志位,来表明这个 buffer 处在哪个队列,比如输入队列或者输出队列(V4L2_BUF_FLAG_QUEUED V4L2_BUF_FLAG_DONE) ,是否关键帧等等,具体可以参照 spec

enum v4l2_memory memory

//V4L2_MEOMORY_MMAP  V4L2_MEMORY_USERPTR  V4L2_MEMORY_OVERLAY

union m

__u32 offset

//  memory 类型是 V4L2_MEOMORY_MMAP 的时候,主要用来表明 buffer  device momory 中相对起始位置的偏移,主要用在 mmap() 参数中,对应用程序没有左右

unsigned long userptr

//  memory 类型是 V4L2_MEMORY_USERPTR 的时候,这是一个指向虚拟内存中 buffer 的指针,由应用程序来设定。

__u32 length

//buffer  size

 driver 内部管理 着两个 buffer queues ,一个输入队列,一个输出队列。对于 capture device 来说,当输入队列中的 buffer 被塞满数据以后会自动变为输出队列,等待调用 VIDIOC_DQBUF 将数据进行处理以后重新调用VIDIOC_QBUF  buffer 重新放进输入队列;对于 output device 来说 buffer 被显示以后自动变为输出队列。

刚初始化的所有 map 过的 buffer 开始都处于 dequeced 的状态,由 driver 来管理对应用程序是不可访问的。对于 capture 应用程序来说,首先是通过 VIDIOC_QBUF 将所有 map 过的 buffer 加入队列,然后通过VIDIOC_STREAMON 开始 capture ,并进入 read loop ,在这里应用程序会等待直到有一个 buffer 被填满可以从队列中 dequeued ,当数据使用完后再 enqueue 进输入队列;对于 output 应用程序来说,首先应用程序会buffer 装满数据然后 enqueued ,当足够的 buffer 进入队列以后就调用 VIDIOC_STREAMON 将数据输出。

有两种方法来阻塞应用程序的执行,直到有 buffer 能被 dequeued ,默认的是当调用 VIDIOC_DQBUF 的时候会被阻塞,直到有数据在 outgoing queue ,但是如果打开设备文件 的时候使用了 O_NONBLOCK ,则当调用VIDIOC_DQBUF 而又没有数据可读的时候就会立即返回。另外一种方法是调用 select  poll 来对文件描述符进行监听是否有数据可读。

VIDIOC_STREAMON  VIDIOC_STREAMOFF 两个 ioctl 用来开始和停止 capturing 或者 output ,而且VIDIOC_STREAMOFF 会删除输入和输出队列中的所有 buffer 

因此 drvier 如果要实现 memory mapping I/O 必须支持 VIDIOC_REQBUFS, VIDIOC_QUERYBUF, VIDIOC_QBUF, VIDIOC_DQBUF, VIDIOC_STREAMON  VIDIOC_STREAMOFF ioctl, the mmap(), munmap(), select()  poll() 函数

 

User Pointers 是一种综合了 Read/Write  memory mappded 优势的 I/O 方法, buffer 是由应用程序自己申请的,可以是在虚拟内存或者共享内存中。在 capture  output 方面基本来说和 memory mapped 方式是相同的,在这里只提一下它申请内存的方式。

User pointer 方式下,申请的内存也 memory page size 为单位对齐,而且 buffersize 也有一定限制,例示代码中是这样计算 buffer size 的,暂时还不知道这样分配 buffer size 的依据是什么,先简单地这样用就好了:

page_size = getpagesize ();

buffer_size = (buffer_size + page_size - 1) & ~(page_size – 1);

buffers[n_buffers].start = memalign ( page_size,

buffer_size);

 

3  start_capturing

经过上面的一系列的数据协商已经 buffer 的分配以后就可以调用 VIDIOC_QBUF  buffer 全部加入输入队列中,并调用 VIDIOC_STREAM0N 开始捕获数据了:

int ioctl(int fd, int request, struct v4l2_buffer *argp);

//VIDIOC_QBUF VIDIOC_DQBUF

int ioctl(int fd, int request, const int *argp);

//VIDIOC_STREAM0N VIDIOC_STREAMOFF  int 参数是 buffer 类型)

 

4  mainloop

开始捕获数据以后就会进入一个主循环,可以使用 select 或者 poll 来监听文件描述符的状态,一旦有数据可读,就调用函数来读取数据。

 

5  read_frame

读取数据根据 I/O 方式的不同而不同:

Read/Write 方式直接从文件描述符中读一个帧大小的数据;

Memory mapped 方式下先从输出队列中 dequeued 一个 buffer ,然后对帧数据进行处理,处理完成以后再放入输入队列。

User pointer 方式下也是首先从输出队列中 dequeued 一个 buffer ,然后对这个 buffer 进行判断,看是否是应用程序开始申请的 buffer ,然后再对这个 buffer 进行处理,最后放入输入队列。

 

6  stop_capturing / uninit_device / close device

最后就是捕捉以及资源释放并关闭 device

关于v4l2,一些注意de地方

首先来看Read/Write,如果VIDIOC_QUERYCAP调用返回的v4l2_capability参数中,V4L2_CAP_READWRITE被设置成真了的话,就说明支持Read/Write I...
  • rekken
  • rekken
  • 2011年03月29日 17:42
  • 1497

Java开发者写SQL时常需要注意的8+13个地方

Java开发者写SQL时常需要注意的8+13个地方 (1)Understanding NULL Is this predicate correct with respect to NULL? ...
  • rosyouth
  • rosyouth
  • 2015年04月08日 19:49
  • 1121

关于重载的概念和使用时的注意事项

本文对重载的概念和一些基本的常见用法作了一些归纳,供读者参阅。
  • qq_38234015
  • qq_38234015
  • 2017年04月24日 11:43
  • 425

关于AIDL一些需要注意的地方

1、从远程客户端进程来的调用是由不同的线程发起的,运行在不同的进程。所以,服务端必须处理好在同一时刻有多个从不同线程过来的请求的情况。也就是说,一个AIDL的实现必须是完成线程安全的,必须手动处理多线...
  • liuyi1207164339
  • liuyi1207164339
  • 2016年06月19日 13:53
  • 4744

关于PopupWindow的一些注意的地方

昨天在做加载的动画的时候,用PopupWindow去弹出加载动画。但是在OnCreate里调用showAtLocation时老是崩溃。出现一下错误: android.view.WindowManage...
  • time__
  • time__
  • 2016年07月08日 13:12
  • 384

关于u3d中需要注意一些地方

在里会持续列举一些u3d中需要注意的事项的,有些是我自己遇过的坑,有些是我收集来的。RenderTexture相关:透明问题 – 5.3.4f如何构建的RenderTexture没有指定RenderT...
  • AnYuanLzh
  • AnYuanLzh
  • 2016年03月29日 09:58
  • 749

linux使用tomcat7.0注意事项

tomcat7.0的最大亮点就是全面支持web3.0并兼容web2.0,以前的版本如tomcat6.0最多支持web2.5,在 linux里用eclipse+tomcat7.0开发web程序时注意在t...
  • linuxchyu
  • linuxchyu
  • 2013年11月27日 14:01
  • 701

关于 UITapGestureRecognizer 一些注意的地方

之前自定义的一个类 +(instancetype)newCustomLanguageDialog:(id)owner containor:(UIView *)container 里加了...
  • sd19871122
  • sd19871122
  • 2016年04月12日 13:41
  • 226

C语言需要注意的地方

今天看了一本C陷阱与指针的书,从中挑选了一些我自己平常不太注意的地方,或者有些是记不太清的东西,稍微整理了下有以下这些地方: 1:=与==是不同的,一个是赋值,一个是比较 2:&与&&是不同的,前...
  • chuhang_zhqr
  • chuhang_zhqr
  • 2016年01月27日 23:10
  • 495

Linux下的V4L2 相关配置

前几天弄linux 下的摄像头,主要是用在嵌入式的图像处理上。关于v4l2的资料比较多的,主要是明白各种数据结构的含义,随便一搜就有很多,这里提供一个写好的示例。 对外接口很简单: 1)通过设备文件...
  • u013672192
  • u013672192
  • 2016年04月15日 20:42
  • 490
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:关于v4l2,一些注意de地方
举报原因:
原因补充:

(最多只允许输入30个字)