ImageVerifierCode 换一换
格式:DOCX , 页数:30 ,大小:42.51KB ,
资源ID:16711183      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/16711183.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(V4L2驱动的移植与应用Word文档下载推荐.docx)为本站会员(b****4)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

V4L2驱动的移植与应用Word文档下载推荐.docx

1、 .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_s_std = vidioc_s_std,

2、 .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, .vidioc_queryctrl = vidioc_queryctrl, .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff,#ifdef CONFIG_VI

3、DEO_V4L1_COMPAT .vidiocgmbuf = vidiocgmbuf,#endif 3) vivi_templatestatic struct video_device vivi_template = .name = vivi, .fops = &vivi_fops, .ioctl_ops = &vivi_ioctl_ops, .minor = -1, .release = video_device_release, .tvnorms = V4L2_STD_525_60, .current_norm = V4L2_STD_NTSC_M,其中函数vivi_xxx和vidioc_x

4、xx都是在vivi.c中实现的。如果要基于某个硬件来实现V4L2的接口,那这些函数就需要调用硬件的驱动去实现。4) vivi_devstructvivi_dev list_head vivi_devlist; /内核双向链表,在内核数据结构里有描述semaphore lock; /信号量,防止竞态访问intusers; /用户数量计数/*various device info */unsigned resources;video_devicevideo_dev; /这个成员是这个结构的核心,用面向对象的话来说就是基类vivi_dmaqueue vidq; /DMA队列Several count

5、ers */h,m,s,us,jiffies; /定时器定义char timestr13; /其它一些资源变量. 像这样变义的结构在Linux C 中很普遍,这也是利用C来实现面向对象编程的强大方法。建立这个结构对象之后,所有的操作都是基于这个结构,或者这个结构派生出的来的其它结构。 5) vivi_fhvivi_fh vivi_dev*dev;video capture */vivi_fmt*fmt; width,height;videobuf_queuevb_vidq;enumv4l2_buf_type type; 这个结构即是vivi_dev结构的更深层次封装,基于那个结构加入了更多的描

6、述信息,如视频制式、视频画面大小、视频缓冲队列等等。在open的时候,会把这个结构赋给file结构中的private_data域。在释放设备时注销.其它的像ioctl,mmap,read,write等等都会用到这个结构,其实整个模块的编写的cdev差不多。只是视频设备的基类是video_device,而字符设备的基类是cdev而已。 2、数据传输方式: 在设备与应用程序之间有三种数据传输方式: 1)read与write这种方式,它像其它设备驱动一样,但是这种方式很慢,对于数据视频流不能满足其要求;2)直接的内存访问,可以通过其映射方式来传输(IO数据流,交换指向缓冲区指针的方法);这是视频设备

7、通常用的方法,采用mmap()的方法,即有内核空间里开辟内存,再在程序里把这部分的内存映射到程序空间。如果有设备内存,即直接映射到设备的内核,这种性能更高。 3)异步IO口访问,但是这种方法在V4L2模块中还没有实现。(重要:需要确认) vivi中的mmap是利用第二种方法来实现的,这也是视频设备常用的方法:staticintvivi_mmap(structfile *file, structvm_area_struct * vma)vivi_fh *fh = file-private_data;ret;dprintk (1,mmap called, vma=0x%08lxn,(unsigne

8、dlong)vma);ret=videobuf_mmap_mapper(&fh-vb_vidq, vma);vma start=0x%08lx, size=%ld, ret=%dn(unsignedlong)vma-vm_start,vm_end-(unsignedret);return videobuf_mmap_mapper(& 这个核心函数把设备的I/O内存或者设备内存映射到系统为它开辟的虚拟内存。 3、操控设备的实现: ioctlvivi_ioctl(structinode *inode, structfile *file, unsignedcmd, unsignedlongarg)v

9、ideo_usercopy(inode, file, cmd, arg, vivi_do_ioctl); vivi_do_ioctl 这个函数里调用一些命令来设备V4L2模块中的一些结构参数来改变或者获取设备的参数。二、V4L2的应用 下面简单介绍一下V4L2驱动的应用流程。1、 视频采集的基本流程一般的,视频采集都有如下流程:2、 打开视频设备在V4L2中,视频设备被看做一个文件。使用open函数打开这个设备:/ 用非阻塞模式打开摄像头设备int cameraFd;cameraFd = open(/dev/video0, O_RDWR | O_NONBLOCK, 0);/ 如果用阻塞模式打开

10、摄像头设备,上述代码变为:/cameraFd = open(, O_RDWR, 0);关于阻塞模式和非阻塞模式:应用程序能够使用阻塞模式或非阻塞模式打开视频设备,如果使用非阻塞模式调用视频设备,即使尚未捕获到信息,驱动依旧会把缓存(DQBUFF)里的东西返回给应用程序。3、 设定属性及采集方式打开视频设备后,可以设置该视频设备的属性,例如裁剪、缩放等。这一步是可选的。在Linux编程中,一般使用ioctl函数来对设备的I/O通道进行管理:extern int ioctl (int _fd, unsigned long int _request, .) _THROW;_fd:设备的ID,例如刚才

11、用open函数打开视频通道后返回的cameraFd;_request:具体的命令标志符。在进行V4L2开发中,一般会用到以下的命令标志符:VIDIOC_REQBUFS:分配内存 VIDIOC_QUERYBUF:把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址 VIDIOC_QUERYCAP:查询驱动功能 VIDIOC_ENUM_FMT:获取当前驱动支持的视频格式 VIDIOC_S_FMT:设置当前驱动的频捕获格式 VIDIOC_G_FMT:读取当前驱动的频捕获格式 VIDIOC_TRY_FMT:验证当前驱动的显示格式 VIDIOC_CROPCAP:查询驱动的修剪能力 VIDIOC_

12、S_CROP:设置视频信号的边框 VIDIOC_G_CROP:读取视频信号的边框 VIDIOC_QBUF:把数据从缓存中读取出来 VIDIOC_DQBUF:把数据放回缓存队列 VIDIOC_STREAMON:开始视频显示函数 VIDIOC_STREAMOFF:结束视频显示函数 VIDIOC_QUERYSTD:检查当前视频设备支持的标准,例如PAL或NTSC。 这些IO调用,有些是必须的,有些是可选择的。4、 检查当前视频设备支持的标准在亚洲,一般使用PAL(720X576)制式的摄像头,而欧洲一般使用NTSC(720X480),使用VIDIOC_QUERYSTD来检测:v4l2_std_id

13、std;do ret = ioctl(fd, VIDIOC_QUERYSTD, &std); while (ret = -1 & errno = EAGAIN);switch (std) case V4L2_STD_NTSC: / case V4L2_STD_PAL:5、 设置视频捕获格式当检测完视频设备支持的标准后,还需要设定视频捕获格式:struct v4l2_format fmt;memset ( &fmt, 0, sizeof(fmt) );fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;fmt.fmt.pix.width = 720;fmt.fmt.pi

14、x.height = 576;fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;if (ioctl(fd, VIDIOC_S_FMT, &fmt) = -1) return -1;v4l2_format结构体定义如下:struct v4l2_format enum v4l2_buf_type type; / 数据流类型,必须永远是V4L2_BUF_TYPE_VIDEO_CAPTURE union struct v4l2_pix_format pix; struct v4l2

15、_window win; struct v4l2_vbi_format vbi; _u8 raw_data200; fmt;struct v4l2_pix_format _u32 width; / 宽,必须是16的倍数 _u32 height; / 高,必须是16的倍数 _u32 pixelformat; / 视频数据存储类型,例如是YUV4:2:2还是RGB enum v4l2_field field; _u32 bytesperline; _u32 sizeimage; enum v4l2_colorspace colorspace; _u32 priv;6、 分配内存接下来可以为视频捕获

16、分配内存:struct v4l2_requestbuffers req;if (ioctl(fd, VIDIOC_REQBUFS, &req) = -1) v4l2_requestbuffers定义如下:struct v4l2_requestbuffers _u32 count; / 缓存数量,也就是说在缓存队列里保持多少张照片 enum v4l2_memory memory; / V4L2_MEMORY_MMAP 或 V4L2_MEMORY_USERPTR _u32 reserved2;7、 获取并记录缓存的物理空间使用VIDIOC_REQBUFS,我们获取了req.count个缓存,下一步

17、通过调用VIDIOC_QUERYBUF命令来获取这些缓存的地址,然后使用mmap函数转换成应用程序中的绝对地址,最后把这段缓存放入缓存队列:typedef struct VideoBuffer void *start; size_t length; VideoBuffer;VideoBuffer* buffers = calloc( req.count, sizeof(*buffers) );struct v4l2_buffer buf;for (numBufs = 0; numBufs req.count; numBufs+) memset( &buf, 0, sizeof(buf) );

18、buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = numBufs; / 读取缓存 if (ioctl(fd, VIDIOC_QUERYBUF, &buf) = -1) buffersnumBufs.length = buf.length; / 转换成相对地址 buffersnumBufs.start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset); if (buffers

19、numBufs.start = MAP_FAILED) / 放入缓存队列 if (ioctl(fd, VIDIOC_QBUF, &8、 关于视频采集方式操作系统一般把系统使用的内存划分成用户空间和内核空间,分别由应用程序管理和操作系统管理。应用程序可以直接访问内存的地址,而内核空间存放的是 供内核访问的代码和数据,用户不能直接访问。v4l2捕获的数据,最初是存放在内核空间的,这意味着用户不能直接访问该段内存,必须通过某些手段来转换地址。一共有三种视频采集方式:1)使用read、write方式:直接使用 read 和 write 函数进行读写。这种方式最简单,但是这种方式会在 用户空间和内核空间

20、不断拷贝数据 ,同时在用户空间和内核空间占用 了 大量内存,效率不高。2)内存映射方式(mmap):把设备里的内存映射到应用程序中的内存控件,直接处理设备内存,这是一种有效的方式。上面的mmap函数就是使用这种方式。3)用户指针模式:内存由用户空间的应用程序分配,并把地址传递到内核中的驱动程序,然后由 v4l2 驱动程序直接将数据填充到用户空间的内存中。这点需要在v4l2_requestbuffers里将memory字段设置成V4L2_MEMORY_USERPTR。第一种方式效率是最低的,后面两种方法都能提高执行的效率,但是对于mmap 方式,文档中有这样一句描述 -Remember the

21、buffers are allocated in physical memory, as opposed to virtual memory which can be swapped out to disk. Applications should free the buffers as soon as possible with the munmap () function .(使用mmap方法的时候,buffers相当于是在内核空间中分配的,这种情况下,这些buffer是不能被交换到虚拟内存中,虽然这种方法不怎么影响读写效率,但是它一直占用着内核空间中的内存,当系统的内存有限的时候,如果同

22、时运行有大量的进程,则对系统的整体性能会有一定的影响。) 所以,对于三种视频采集方式的选择,推荐的顺序是 userptr 、 mmap 、 read-write 。当使用 mmap 或 userptr 方式的时候,有一个环形缓冲队列的概念,这个队列中,有 n 个 buffer ,驱动程序采集到的视频帧数据,就是存储在每个 buffer 中。在每次用 VIDIOC_DQBUF 取出一个 buffer ,并且处理完数据后,一定要用 VIDIOC_QBUF 将这个 buffer 再次放回到环形缓冲队列中。环形缓冲队列,也使得这两种视频采集方式的效率高于直接 read/write 。9、 处理采集数据

23、V4L2有一个数据缓存,存放req.count数量的缓存数据。数据缓存采用FIFO的方式,当应用程序调用缓存数据时,缓存队列将最先采集到的 视频数据缓存送出,并重新采集一张视频数据。这个过程需要用到两个ioctl命令,VIDIOC_DQBUF和VIDIOC_QBUF:memset(&buf,0,sizeof(buf);buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory=V4L2_MEMORY_MMAP;buf.index=0;/读取缓存if (ioctl(cameraFd, VIDIOC_DQBUF, &buf) = -1)/视频处理算法/重新放入缓

24、存队列if (ioctl(cameraFd, VIDIOC_QBUF, &10、 关闭视频设备使用close函数关闭一个视频设备close(cameraFd)三、V4L2的democapture.c是官方示例程序。capture.c 程序中的 process_image 函数: capture.c 程序主要是用来演示怎样使用 v4l2 接口,并没有对采集到的视频帧数据做任何实际的处理,仅仅用 process_image 函数表示了处理图像的代码位置。 process_image 函数只有一个参数,就是存储视频帧的内存的地址指针,但是在真正的应用中,通常还需要知道该指针指向的数据的大小。 因此可以修改函数,改成 void process_image ( const void * p, int len ) ,但是每次调用 process_image 的时候,第 2 个参数该传递什么值?考虑

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1