• (六) 编写vivid



    title: 编写vivid
    date: 2019/4/23 19:40:00
    toc: true

    编写vivid

    新内核对video_buf的封装更好了,很多函数基本上套个名字就好了,这个可以参考

    下面的分析是韦老师的2.x版本的,基本流程如下

    1.注册平台设备和驱动;
    2.probe()函数:
      a.分配video_device;
      b.设置video_device,包括:release、fops、ioctl_ops、v4l2_dev;
      c.注册设置video_device;
      d.其它:定义/初始化自旋锁/定时器;
    3.填充操作函数v4l2_file_operations:
      a.open():初始buf化队列和设置定时器;
      b.close():删除定时器和释放buf队列;
      c.mmap():调用videobuf_mmap_mapper开辟虚拟内存;
      d.poll():调用videobuf_poll_stream实现poll机制非阻塞访问;
    4.填充操作函数v4l2_ioctl_ops:
      前面介绍的11个必须ioctl,几乎都是调用内核提供的API;
    5.填充操作函数videobuf_queue_ops:
      对buf进行一些操作;
    6.填充数据:
      利用定时器,不断产生数据并唤醒进程,实现获取到图像采集数据;
    

    细致流程如下

    请求缓冲区 VIDIOC_QUERYBUF
    	v4l2_fops
    		v4l2_file_operations vivi_fops .unlocked_ioctl = video_ioctl2
    			__video_do_ioctl
    				ops->vidioc_querybuf(file, fh, p);		//.vidioc_querybuf      = vidioc_querybuf,
    					vidioc_querybuf
    						vb2_querybuf(&dev->vb_vidq, p)
    查询缓冲区 VIDIOC_QUERYBUF  
    	ops->vidioc_querybuf(file, fh, p)
    		vb2_querybuf(&dev->vb_vidq, p)
    			vb = q->bufs[b->index]
    			__fill_v4l2_buffer(vb, b)  填充 v4l2_buffer  获得缓冲区的格式大小等信息
    			
    vivi_mmap
    	v4l2_fops.v4l2_mmap  >  vdev->fops->mmap
    		vivi_mmap
    			vb2_mmap(&dev->vb_vidq, vma)
    				ret = call_memop(q, mmap, vb->planes[plane].mem_priv, vma); 
    				// 搜索
    					#define call_memop(q, op, args...)					
    						(((q)->mem_ops->op) ?						
    							((q)->mem_ops->op(args)) : 0)
    
    						q->ops = &vivi_video_qops;
    						q->mem_ops = &vb2_vmalloc_memops;
    						
    				也就是调用		vb2_vmalloc_memops.mmap
    					vb2_vmalloc_mmap
    						remap_vmalloc_range
    
    放入队列 VIDIOC_QBUF
    	ops->vidioc_qbuf
    		vb2_qbuf(&dev->vb_vidq, p)
    					call_qop(q, wait_prepare, q);
    					down_read(mmap_sem);
    					call_qop(q, wait_finish, q);
    		list_add_tail(&vb->queued_entry, &q->queued_list);
    		__enqueue_in_driver(vb);  这里执行驱动自身可能需要的入队列后的初始化
    		__fill_v4l2_buffer(vb, b);
    
    启动摄像头 VIDIOC_STREAMON		
    	vb2_streamon		
    		start_streaming
    		q->streaming = 1;
    		
    		
    v4l2_poll
    	vdev->fops->poll
    		vivi_poll
    			搜索 wait
    			队列 	DECLARE_WAITQUEUE(wait, current);
    			
    			timeout = msecs_to_jiffies(frames_to_ms(1));
    			vivi_thread_tick(dev);
    				vb2_buffer_done
    					wake_up(&q->done_wq);  //唤醒
    //创建了一个线程			
    static int vivi_thread(void *data)
    {
    	vivi_sleep(dev);		//具体30ms唤醒一次
    	
    	#define frames_to_ms(frames)					
    	((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR)
    #define WAKE_NUMERATOR 30
    
    	
    }	
    
    
    VIDIOC_DQBUF  取出缓冲
    ops->vidioc_dqbuf
    	vb2_dqbuf(&dev->vb_vidq, p, file->f_flags & O_NONBLOCK)
    		call_qop(q, buf_finish, vb)
    		list_del(&vb->queued_entry);
    		vb->state = VB2_BUF_STATE_DEQUEUED;
    
  • 相关阅读:
    js之自定义鼠标右键菜单
    js之键盘控制div移动
    js之select标签---省市联动小例子
    html之浮动和定位
    java开发简单的用户管理系统
    ASP.NET Web API 2中的属性路由(Attribute Routing)
    ASP.NET Web API中的路由
    Web API 2中的操作结果
    WebApi~通过HttpClient来调用Web Api接口
    Quartz.NET 作业调度
  • 原文地址:https://www.cnblogs.com/zongzi10010/p/10764240.html
Copyright © 2020-2023  润新知