重头写一个v4l2的虚拟驱动_3
来源:互联网 发布:医疗器械注册软件研究 编辑:程序博客网 时间:2024/05/20 19:47
简介
因为在qcom平台上和linux原生都是用的v4l2框架作为camera的驱动框架,所以本着学习记录的笔记,做了如下文档记录。该文档是学习《卫东山老师视频教程第三期》的个人学习笔记,非常感谢老师的资料。该记录仅供学习交流,如有侵犯到大家利益,还望海涵,请联系博主删除。
poll/select
在前一篇中我们说到,应用程序和驱动通过select/poll机制来进行交互,从而做到不停地qbuffer和dequebuffer。所以驱动中还需要实现它的poll函数:
static unsigned int myvivi_poll(struct file *file, struct poll_table_struct *wait){ return videobuf_poll_stream(file, &myvivi_vb_vidqueue, wait);} static const struct v4l2_file_operations myvivi_fops = { ............. .poll = myvivi_poll, .............};
在videobuf_poll_stream函数中,如果队列myvivi_vb_vidqueue中没有数据,那么进程就会队列的第一个buffer上面,利用queuebuf->done进入休眠。
定时器模拟数据
最后使用定时器来模拟产生数据。 首先在驱动中添加定时器:
static struct timer_list myvivi_timer; static int myvivi_open(struct file *file){ ............ myvivi_timer.expires = jiffies + 1; add_timer(&myvivi_timer); ........}static int myvivi_close(struct file *file){ del_timer(&myvivi_timer); ...........} static int myvivi_init(void){ ............ init_timer(&myvivi_timer); myvivi_timer.function = myvivi_timer_function;}
另外还需要一个之前提到过的本地队列和在myvivi_buffer_prepare做准备工作:
static struct list_head myvivi_vb_local_queue; static int myvivi_buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, enum v4l2_field field){ /* 0. 设置videobuf */ vb->size = myvivi_format.fmt.pix.sizeimage; vb->bytesperline = myvivi_format.fmt.pix.bytesperline; vb->width = myvivi_format.fmt.pix.width; vb->height = myvivi_format.fmt.pix.height; vb->field = field; vb->state = VIDEOBUF_PREPARED; return 0;} static void myvivi_buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb){ vb->state = VIDEOBUF_QUEUED; /* 把videobuf放入本地一个队列尾部 * 定时器处理函数就可以从本地队列取出videobuf */ list_add_tail(&vb->queue, &myvivi_vb_local_queue);}static int myvivi_init(void){ ............. INIT_LIST_HEAD(&myvivi_vb_local_queue); .............}
在驱动入口函数中初始化了定时器myvivi_timer和本地队列myvivi_vb_local_queue,接着在open函数中add_timer和在release函数中删除定时器。然后在myvivi_buffer_prepare函数中填充了数据的大小、宽度之类信息到videobuf中,将videobuf放到本地队列myvivi_vb_local_queue中。
定时器函数
最后就是在定时器函数中来模拟数据。
static void myvivi_timer_function(unsigned long data){ struct videobuf_buffer *vb; void *vbuf; struct timeval ts; /* 1. 构造数据: 从队列头部取出第1个videobuf, 填充数据*/ /* 1.1 从本地队列取出第1个videobuf */ if (list_empty(&myvivi_vb_local_queue)) { goto out; } vb = list_entry(myvivi_vb_local_queue.next, struct videobuf_buffer, queue); /* Nobody is waiting on this buffer, return */ if (!waitqueue_active(&vb->done)) goto out; /* 1.2 填充数据 */ vbuf = videobuf_to_vmalloc(vb); /*得到它的虚拟地址*/ memset(vbuf, 0x88, vb->size); vb->field_count++; do_gettimeofday(&ts); vb->ts = ts; vb->state = VIDEOBUF_DONE; /* 1.3 把videobuf从本地队列中删除 */ list_del(&vb->queue); /* 2. 唤醒进程: 唤醒videobuf->done上的进程 */ wake_up(&vb->done); out: /* 3. 修改timer的超时时间 : 30fps, 1秒里有30帧数据 * 每1/30 秒产生一帧数据 */ mod_timer(&myvivi_timer, jiffies + HZ/30);}
之前有说到,myvivi_buffer_queue将queuebuf放入到了本地队列myvivi_vb_local_queue中。定时器函数就从本地队列中取出第一个queuebuf,如果本地队列为空,就直接退出,如果没用进程通过poll被阻塞在vb->done上,也直接退出。 接着利用videobuf_to_vmalloc或得在本地队列上得到的queuebuf虚拟地址,用最简单的msmset将这一帧数据全部填充为0x88,大小为之前myvivi_buffer_prepare填充进来的vb->size = myvivi_format.fmt.pix.sizeimage; 在往后,累加已经产生的帧数和填充当前时间,最重要的设置当前的videobuf_buffer状态为VIDEOBUF_DONE,否者被阻塞休眠的进程即使被唤醒了也不会正常返回。接着本地队列上删除掉当前的videobuf,然后唤醒poll上休眠等待的进程。 最后的HZ/30,表示一秒钟定时器函数运行大约30次,也就是模拟video的帧率为30fps
效果演示
最后也是使用xawtv来做效果演示如下:
通过修改定时器函数中memset中的填充数据值,就可以改变xawtv中显示出来的颜色。
1 0
- 重头写一个v4l2的虚拟驱动_3
- 重头写一个v4l2的虚拟驱动_1
- 重头写一个v4l2的虚拟驱动_2
- linux应用项目(二)摄像头(2)从零写一个V4L2虚拟摄像头驱动之详细分析
- v4l2虚拟驱动的应用测试程序讲解
- V4L2(三)编写虚拟摄像头驱动
- V4L2的视频驱动
- 一个基于v4l2框架的输出驱动分析
- V4L2(二)虚拟摄像头驱动vivi深入分析
- 驱动层之V4L2的驱动框架
- v4l2框架的虚拟视频驱动程序详解
- v4l2 驱动
- 写一个最简单的WDM驱动
- 写一个最简单的WDM驱动
- 如何写一个简单的linux驱动
- 写了一个pca9633的iic驱动
- Linux下面一个简单的虚拟platform驱动
- Linux下面一个简单的虚拟platform驱动
- (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年年终总结:写书成长,承载收获
- PAT A1005 Spell It Right
- 模电书籍推荐
- 【总结】 - OC内存管理(1)
- Java对象的浅层复制
- hadoop实战基础篇(一)
- Android中Parcelable的使用