虚拟视频驱动vivi.c分析

——————/内核版本2.6.31
分析哪些ioctl是必须的,分析应用程序如何获得摄像头数据
root@lyl:~# modprobe vivi
从xawtv的main开始分析涉及哪些系统调用,但该过程太复杂,采用下法:
[root@localhost xm]# strace -o xawtv.log xawtv //260k
xawtv涉及系统调用:
1. open
2. VIDIOC_QUERYCAP
3. for VIDIOC_ENUMINPUT
4. for VIDIOC_ENUMSTD
5. for VIDIOC_ENUM_FMT
6. VIDIOC_G_PARM
7. for VIDIOC_QUERYCTRL //查询属性(如亮度最大值、最小值)
8. VIDIOC_G_STD
9. VIDIOC_G_INPUT
10. VIDIOC_G_CTRL
11. VIDIOC_TRY_FMT
12. VIDIOC_S_FMT
13. VIDIOC_REQBUFS
14. for VIDIOC_QUERYBUF mmap
15. for VIDIOC_QBUF
16. VIDIOC_STREAMON
17. for VIDIOC_S_CTRL、VIDIOC_S_INPUT 、VIDIOC_S_STD
18. for select、VIDIOC_DQBUF、VIDIOC_QBUF
循环将缓冲区放入队列,select查询,若有数据再取出队列,处理完再放入队列
——————/精简ioctl,保留最小集合
static const struct v4l2_ioctl_ops 	vivi_ioctl_ops = {
	.vidioc_querycap      = vidioc_querycap, //缺少则不知设备类型
	//列举、获得、测试、设置摄像头数据的格式,必不可少
	.vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
	.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_streamon      = vidioc_streamon,	
	.vidioc_streamoff     = vidioc_streamoff,
/*
	.vidioc_s_std         = vidioc_s_std,
	.vidioc_enum_input    = vidioc_enum_input,	
	//枚举输入源,去掉xawtv界面video source变为unknown,之前为Camera 0-3
	.vidioc_g_input       = vidioc_g_input,
	.vidioc_s_input       = vidioc_s_input,
	.vidioc_log_status    = v4l2_ctrl_log_status,
	.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
	.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
*/
};
——————/
VIDIOC_ENUMSTD感觉制式对模拟量而言,对数字摄像头无用处
case VIDIOC_ENUMSTD:	//v4l2_ioctl.c
	v4l2_std_id id = vfd->tvnorms
	if (id == 0)
		break;
case VIDIOC_G_STD:
	if (ops->vidioc_g_std)
		ret = ops->vidioc_g_std(file, fh, id);
	else if (vfd->current_norm) 
	{
		ret = 0;
		*id = vfd->current_norm;
	}

struct 	video_device 	vivi_template = {
…………
	.tvnorms              = V4L2_STD_525_60,
	.current_norm         = V4L2_STD_NTSC_M,
};
将上两项去掉,xawtv界面TV norm变为unknown但不影响,故:
.vidioc_s_std = vidioc_s_std, 也可去掉
——————/
将vidioc_queryctrl、vidioc_g_ctrl、vidioc_s_ctrl去掉后

——————/数据获取过程:
1、VIDIOC_REQBUFS
vidioc_reqbufs
	videobuf_reqbufs(&fh->vb_vidq, p)	
		videobuf_mmap_setup
			videobuf_alloc
				kzalloc(sizeof(struct vivi_buffer),GFP_KERNEL);
					struct videobuf_buffer vb;

	/*	(struct videobuf_queue *q 、struct v4l2_requestbuffers *  req)
	vb_vidq在open函数被videobuf_queue_init初始化
	v4l2_requestbuffers包含所要求分配的缓冲区数目,至少为2,
	但没包含缓冲区大小,因真正缓存还未分配(分配count* sizeof(struct vivi_buffer))	*/
2、VIDIOC_QUERYBUF
videobuf_querybuf
	videobuf_status (struct videobuf_queue *q, struct v4l2_buffer *b,
			    struct videobuf_buffer *vb, enum v4l2_buf_type type)
		b->length    = vb->bsize;
		b->m.offset  = vb->boff;
		b->type     = type;
		……

v4l2_mmap		//(参数含"大小")此处真正分配内存
	vivi_mmap
		videobuf_mmap_mapper
			CALL(q, mmap_mapper, q, vma);
				__videobuf_mmap_mapper
					struct videobuf_vmalloc_memory *mem;
					mem = q->bufs[first]->priv;
					pages = PAGE_ALIGN(vma->vm_end - vma->vm_start);
					mem->vmalloc = vmalloc_user(pages); 
3、VIDIOC_QBUF
videobuf_qbuf(struct videobuf_queue *q,struct v4l2_buffer *b)
	struct videobuf_buffer *buf;
	buf = q->bufs[b->index];
	retval = q->ops->buf_prepare(q, buf, field);		//预处理
	list_add_tail(&buf->stream, &q->stream);
	q->ops->buf_queue(q, buf);
4、VIDIOC_STREAMON
videobuf_streamon(struct videobuf_queue *q)
	q->streaming = 1;	//标志位
5、select查询是否有数据
vivi_poll
	videobuf_poll_stream(struct file *file,struct videobuf_queue *q,poll_table *wait)
		struct videobuf_buffer *buf = NULL;
		//从队列头部获得一个缓冲区
		buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
		//如缓冲区没数据则休眠                			
		poll_wait(file, &buf->done, wait);

谁产生数据、唤醒?
内核线程vivi_thread每30MS执行一次,调用vivi_thread_tick
vivi_thread_tick
	vivi_fillbuff(fh, buf);  	// 构造数据
	wake_up(&buf->vb.done);  // 唤醒进程
6、有数据VIDIOC_DQBUF
videobuf_dqbuf
retval = stream_next_buffer(q, &buf, nonblocking);	
list_del(&buf->stream);	//在队列里获得有数据的缓冲区并删掉
	videobuf_status(q, b, buf, q->type);  //将该缓冲区状态返回给APP
7、APP根据VIDIOC_DQBUF,知哪一缓冲区有数据就去读对应地址

怎么写摄像头驱动:
1、分配video_device : video_device_alloc //struct v4l2_device不重要
2、设置
.fops
.ioctl_ops (11项)
如要用内核提供的缓冲区操作函数,还需构造一videobuf_queue_ops
3、注册video_register_device
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值