重头写一个v4l2的虚拟驱动_2
来源:互联网 发布:列主元三角分解法C语言 编辑:程序博客网 时间:2024/06/07 04:45
简介
因为在qcom平台上和linux原生都是用的v4l2框架作为camera的驱动框架,所以本着学习记录的笔记,做了如下文档记录。该文档是学习《卫东山老师视频教程第三期》的个人学习笔记,非常感谢老师的资料。该记录仅供学习交流,如有侵犯到大家利益,还望海涵,请联系博主删除。
buffer队列操作
首先是填充了队列相关的4个函数:
static int myvivi_vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *p){ return (videobuf_reqbufs(&myvivi_vb_vidqueue, p));} static int myvivi_vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p){ return (videobuf_querybuf(&myvivi_vb_vidqueue, p));} static int myvivi_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p){ return (videobuf_qbuf(&myvivi_vb_vidqueue, p));} static int myvivi_vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p){ return (videobuf_dqbuf(&myvivi_vb_vidqueue, p, file->f_flags & O_NONBLOCK));} static int myvivi_vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i){ return videobuf_streamon(&myvivi_vb_vidqueue);} static int myvivi_vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i){ videobuf_streamoff(&myvivi_vb_vidqueue); return 0;} static const struct v4l2_ioctl_ops myvivi_ioctl_ops = { ................. /* 缓冲区操作: 申请/查询/放入队列/取出队列 */ .vidioc_reqbufs = myvivi_vidioc_reqbufs, .vidioc_querybuf = myvivi_vidioc_querybuf, .vidioc_qbuf = myvivi_vidioc_qbuf, .vidioc_dqbuf = myvivi_vidioc_dqbuf, // 启动/停止 .vidioc_streamon = myvivi_vidioc_streamon, .vidioc_streamoff = myvivi_vidioc_streamoff, }
这四个队列相关函数分别用在申请队列、查询队列、放入队列、取出队列、启动和停止的相关buffer数据操作中,都是直接使用的v4l2提供的现成函数
初始化和销毁buffer队列
前面说到了对buffer队列的操作,操作的队列为myvivi_vb_vidqueue,那么在使用它之前,肯定有初始化的操作;在使用完了之后有销毁的操作。对应的操作函数在:
static struct videobuf_queue myvivi_vb_vidqueue; static int myvivi_open(struct file *file){ /* 队列操作2: 初始化 */ videobuf_queue_vmalloc_init(&myvivi_vb_vidqueue, &myvivi_video_qops, NULL, &myvivi_queue_slock, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED, sizeof(struct videobuf_buffer), NULL, &lock); /* 倒数第3个参数是buffer的头部大小 */ return 0;} static int myvivi_close(struct file *file){ videobuf_stop(&myvivi_vb_vidqueue); videobuf_mmap_free(&myvivi_vb_vidqueue); return 0;} static int myvivi_mmap(struct file *file, struct vm_area_struct *vma){ return videobuf_mmap_mapper(&myvivi_vb_vidqueue, vma);} static const struct v4l2_file_operations myvivi_fops = { .owner = THIS_MODULE, .open = myvivi_open, .release = myvivi_close, .mmap = myvivi_mmap, .ioctl = video_ioctl2, /* V4L2 ioctl handler */};
在open函数中,利用videobuf_queue_vmalloc_init对myvivi_vb_vidqueue队列进行了初始化,并且分配了队列头的空间大小,和关联了该队列的一个相关操作函数myvivi_video_qops。 在close函数中,先停止了myvivi_vb_vidqueue队列的使用,然后释放掉它。 在myvivi_mmap函数中,为队列myvivi_vb_vidqueue分配真正的数据空间,前面的open函数只分配了数据头的空间。
关联的myvivi_video_qops
前面讲到在open函数的videobuf_queue_vmalloc_init初始化的时候关联了一个myvivi_video_qops操作函数。对应的代码如下:
/* 参考documentations/video4linux/v4l2-framework.txt: * drivers\media\video\videobuf-core.c ops->buf_setup - calculates the size of the video buffers and avoid they to waste more than some maximum limit of RAM; ops->buf_prepare - fills the video buffer structs and calls videobuf_iolock() to alloc and prepare mmaped memory; ops->buf_queue - advices the driver that another buffer were requested (by read() or by QBUF); ops->buf_release - frees any buffer that were allocated. */ static struct list_head myvivi_vb_local_queue; /* ------------------------------------------------------------------ Videobuf operations ------------------------------------------------------------------*//* APP调用ioctl VIDIOC_REQBUFS时会导致此函数被调用, * 它重新调整count和size */static int myvivi_buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size){ *size = myvivi_format.fmt.pix.sizeimage; if (0 == *count)*count = 32; return 0;} /* APP调用ioctlVIDIOC_QBUF时导致此函数被调用, * 它会填充video_buffer结构体并调用videobuf_iolock来分配内存(只有在V4L2_MEMORY_USERPTR,也就是在用户空间的应用中开辟时候才会 × 使用它来分配内存,这里是使用的类型为:V4L2_MEMORY_MMAP,在内核空间开辟的,所以不需要使用videobuf_iolock) * */static int myvivi_buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,enum v4l2_field field){vb->state = VIDEOBUF_PREPARED; return 0;} /* APP调用ioctl VIDIOC_QBUF时: * 1. 先调用buf_prepare进行一些准备工作 * 2. 把buf放入stream队列 * 3. 调用buf_queue(起通知、记录作用) */static void myvivi_buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb){vb->state = VIDEOBUF_QUEUED; /* 把videobuf放入本地一个队列尾部 */list_add_tail(&vb->queue, &myvivi_vb_local_queue);} /* APP不再使用队列时, 用它来释放内存 */static void myvivi_buffer_release(struct videobuf_queue *vq,struct videobuf_buffer *vb){videobuf_vmalloc_free(vb);vb->state = VIDEOBUF_NEEDS_INIT;} static struct videobuf_queue_ops myvivi_video_qops = {.buf_setup = myvivi_buffer_setup, /* 计算大小以免浪费 */.buf_prepare = myvivi_buffer_prepare,.buf_queue = myvivi_buffer_queue,.buf_release = myvivi_buffer_release,};
myvivi_buffer_setup:用来计算需要分配的数据空间大小和空间的多少,如代码所示,我们设置的数据空间大小为之前计算出来的image size的大小, 分配的空间为32个(一般来说分配空间的范围为2-32个)。 myvivi_buffer_prepare:进行一些qbuffer之前的准备操作,并将队列状态改变为VIDEOBUF_PREPARED。 myvivi_buffer_queue:将队列中的数据放入一个本地队列中,等待被取走,同时将队列状态改变为VIDEOBUF_QUEUED。 myvivi_buffer_release:释放掉队列,同时将它状态改变为初始状态:VIDEOBUF_NEEDS_INIT。
调用关系
1、应用程序首先调用了open函数,初始化了videobuf_queue队列。 2、调用请求队列操作函数: myvivi_vidioc_reqbufs-->videobuf_reqbufs(&myvivi_vb_vidqueue, p) 在videobuf_reqbufs函数中又调用了之前在open-->videobuf_queue_vmalloc_init函数中关联的 myvivi_video_qops-->myvivi_buffer_setup 获得了需要分配的队列数据空间大小和空间块数。 3、调用请求队列操作函数: myvivi_vidioc_querybufs-->videobuf_querybuf 在该函数中查询和返回队列相关信息。 4、调用函数: myvivi_fops-->myvivi_mmap-->videobuf_mmap_mapper 为队列分配真正的数据空间。 5、调用操作函数: myvivi_vidioc_qbufs-->videobuf_qbuf 在函数videobuf_qbuf中又调用到: myvivi_video_qops-->myvivi_buffer_prepare myvivi_video_qops-->myvivi_buffer_queue 在函数myvivi_buffer_prepare中进行一些准备工作,然后在myvivi_buffer_queue中将队列中的数据保存到本地队列myvivi_vb_local_queue中。 6、调用操作函数: yvivi_vidioc_qbufs-->myvivi_vidioc_dqbuf 在myvivi_vidioc_dqbuf中,清除掉已经使用过了的队列数据。
7、利用select/poll机制检测,让步骤5和6不断循环,使得video数据不停的刷新。
1 0
- 重头写一个v4l2的虚拟驱动_2
- 重头写一个v4l2的虚拟驱动_1
- 重头写一个v4l2的虚拟驱动_3
- linux应用项目(二)摄像头(2)从零写一个V4L2虚拟摄像头驱动之详细分析
- v4l2虚拟驱动的应用测试程序讲解
- V4L2(三)编写虚拟摄像头驱动
- V4L2的视频驱动
- 一个基于v4l2框架的输出驱动分析
- V4L2(二)虚拟摄像头驱动vivi深入分析
- 驱动层之V4L2的驱动框架
- v4l2框架的虚拟视频驱动程序详解
- v4l2 驱动
- 写一个最简单的WDM驱动
- 写一个最简单的WDM驱动
- 如何写一个简单的linux驱动
- 写了一个pca9633的iic驱动
- Linux下面一个简单的虚拟platform驱动
- Linux下面一个简单的虚拟platform驱动
- 2015新年好
- BZOJ 2502 上下界网络流
- 重头写一个v4l2的虚拟驱动_1
- J2EE框架搭建大集合
- spoj12943 Counting dp
- 重头写一个v4l2的虚拟驱动_2
- (hdu step 4.3.3)Sum It Up(从n个数中选出m个数让他们的和达到指定和targetSum,输出所有的合法序列)
- POJ 4052-Hrinity(KMP算法+AC自动机)
- android中对字符串的复数处理方法
- 辛星浅析Redis中的pub/sub功能
- Reduce对Pig作业性能的影响
- 重头写一个v4l2的虚拟驱动_3
- [WCF权限控制]从两个重要的概念谈起:Identity与Principal
- 2014年年终总结:写书成长,承载收获