videobuf处理流程

转载自:http://blog.csdn.net/panda19881/article/details/8748934

 

videobuf是应用程序和v4l2驱动程序的一个中间层,用它来进行视频数据缓冲区的分配和管理。

它根据应用程序的需求(缓冲区的数量的大小),分配相应的视频缓冲区,这个缓冲区是在内核空间分配的,并通过mmap方法映射到用户空间,在内核空间形成一个缓冲区队列,在应用程序中有相应的缓冲区数组对应,它们指向的内存地址是一样的。在驱动程序中,根据配置的硬件参数(FIFO阈值),将vip硬件图像存储器中的数据放到缓冲区队列中的 每个缓冲区,然后等待应用程序来读取该缓冲区的数据。videobuf主要由一些特殊的数据结构和ioctl调用组成,下边对其做整体分析:

一、 初始化

初始化缓冲区队列:
1、驱动层的调用
在v4l2_vip.c文件中:

  1. static int vip_open(struct file *file) 
  2. struct vip_dev *dev = video_drvdata(file); 
  3. struct vip_fh *fh = NULL; 
  4. int retval = 0; 
  5.  
  6. 、、、、、、、、、 
  7.  
  8. /*allocate and initialize per filehandle data*/ 
  9. fh = kzalloc(sizeof(*fh), GFP_KERNEL);//此时已经把vb_vidq成员的空间分配好 
  10. if(NULL == fh){ 
  11.   dev->users--; 
  12.   retval = -ENOMEM; 
  13.  
  14. 、、、、、、、、、、 
  15.  
  16. fh->type    = V4L2_BUF_TYPE_VIDEO_CAPTURE; 
  17. fh->fmt    = &formats[0]; 
  18.  
  19. 、、、、、、、、 
  20.  
  21. /*初始化videobuf缓冲区队列 vip_video_qops 是驱动层的videobuf回掉函数*/ 
  22. videobuf_queue_vmalloc_init(&fh->vb_vidq, &vip_video_qops, NULL, 
  23.      &dev->slock, fh->type,  V4L2_FIELD_INTERLACED, 
  24.      sizeof(struct vip_buffer), fh); 
  25. return 0; 
static int vip_open(struct file *file)
{
 struct vip_dev *dev = video_drvdata(file);
 struct vip_fh *fh = NULL;
 int retval = 0;

、、、、、、、、、

 /*allocate and initialize per filehandle data*/
 fh = kzalloc(sizeof(*fh), GFP_KERNEL);//此时已经把vb_vidq成员的空间分配好
 if(NULL == fh){
  dev->users--;
  retval = -ENOMEM;
 }

、、、、、、、、、、

 fh->type    = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 fh->fmt    = &formats[0];

、、、、、、、、

 /*初始化videobuf缓冲区队列 vip_video_qops 是驱动层的videobuf回掉函数*/
 videobuf_queue_vmalloc_init(&fh->vb_vidq, &vip_video_qops, NULL,
     &dev->slock, fh->type,  V4L2_FIELD_INTERLACED,
     sizeof(struct vip_buffer), fh);
 return 0;
}


2、videobuf层的操作
在videobuf-vmalloc.c中:

  1. videobuf_queue_vmalloc_init(struct videobuf_queue *q, 
  2.     struct videobuf_queue_ops *ops, 
  3.     struct device *dev, 
  4.     spinlock_t *irqlock, 
  5.     enum v4l2_buf_type type, 
  6.     enum v4l2_field field, 
  7.     unsigned int msize, 
  8.     void *priv 
  9. ) 
  10. videobuf_queue_core_init(q, ops, dev, irlock, type, field, msize, priv, &qops); 
  11.  
  12. //上边函数多了一个qops参数,它是 videobuf层的数据操作函数集 
  13. void videobuf_queue_core_init(struct videobuf_queue *q, 
  14.     struct videobuf_queue_ops *ops, 
  15.     struct device *dev, 
  16.     spinlock_t *irqlock, 
  17.     enum v4l2_buf_type type, 
  18.     enum v4l2_field field, 
  19.     unsigned int msize, 
  20.     void *priv, 
  21.     struct videobuf_qtype_ops *int_ops) 
  22. BUG_ON(!q); 
  23. memset(q, 0, sizeof(*q)); 
  24. //初始化队列的一些成员 
  25. q->irqlock   = irqlock; 
  26. q->dev       = dev; 
  27. q->type      = type; 
  28. q->field     = field; 
  29. q->msize     = msize; 
  30. q->ops       = ops; 
  31. q->priv_data = priv; 
  32. q->int_ops   = int_ops; 
  33.  
  34. //检测必要的成员数据是否不为空 
  35. /* All buffer operations are mandatory */ 
  36. BUG_ON(!q->ops->buf_setup); 
  37. BUG_ON(!q->ops->buf_prepare); 
  38. BUG_ON(!q->ops->buf_queue); 
  39. BUG_ON(!q->ops->buf_release); 
  40.  
  41. /* Lock is mandatory for queue_cancel to work */ 
  42. BUG_ON(!irqlock); 
  43.  
  44. /* Having implementations for abstract methods are mandatory */ 
  45. BUG_ON(!q->int_ops); 
  46.  
  47. mutex_init(&q->vb_lock);//初始化自旋锁 
  48. init_waitqueue_head(&q->wait);//初始化videobuf队列queue中的等待队列 
  49. INIT_LIST_HEAD(&q->stream);//初始化链表 
videobuf_queue_vmalloc_init(struct videobuf_queue *q,
    struct videobuf_queue_ops *ops,
    struct device *dev,
    spinlock_t *irqlock,
    enum v4l2_buf_type type,
    enum v4l2_field field,
    unsigned int msize,
    void *priv
)
{
 videobuf_queue_core_init(q, ops, dev, irlock, type, field, msize, priv, &qops);
}

//上边函数多了一个qops参数,它是 videobuf层的数据操作函数集
void videobuf_queue_core_init(struct videobuf_queue *q,
    struct videobuf_queue_ops *ops,
    struct device *dev,
    spinlock_t *irqlock,
    enum v4l2_buf_type type,
    enum v4l2_field field,
    unsigned int msize,
    void *priv,
    struct videobuf_qtype_ops *int_ops)
{
 BUG_ON(!q);
 memset(q, 0, sizeof(*q));
//初始化队列的一些成员
 q->irqlock   = irqlock;
 q->dev       = dev;
 q->type      = type;
 q->field     = field;
 q->msize     = msize;
 q->ops       = ops;
 q->priv_data = priv;
 q->int_ops   = int_ops;

//检测必要的成员数据是否不为空
 /* All buffer operations are mandatory */
 BUG_ON(!q->ops->buf_setup);
 BUG_ON(!q->ops->buf_prepare);
 BUG_ON(!q->ops->buf_queue);
 BUG_ON(!q->ops->buf_release);

 /* Lock is mandatory for queue_cancel to work */
 BUG_ON(!irqlock);

 /* Having implementations for abstract methods are mandatory */
 BUG_ON(!q->int_ops);

 mutex_init(&q->vb_lock);//初始化自旋锁
 init_waitqueue_head(&q->wait);//初始化videobuf队列queue中的等待队列
 INIT_LIST_HEAD(&q->stream);//初始化链表
}


二、 videobuf的相关ioctl()操作
这些操作有三部分组成,1是应用程序通过ioctl函数调用v4l2驱动中实现的接口函数,2这些接口函数在调用videobuf层的响应函数来做出处理,3如果有的处理参数需要v4l2层来决定的话,就调用v4l2层的videobuf设置函数。

1、ioctl接口函数列表

  1. static const struct v4l2_ioctl_ops vip_capture_ioctl_fops = { 
  2.  
  3. 、、、、、、 
  4.  
  5. .vidioc_reqbufs  = vip_reqbufs, 
  6. .vidioc_querybuf = vip_querybuf, 
  7. .vidioc_qbuf  = vip_qbuf, 
  8. .vidioc_dqbuf  = vip_dqbuf, 
  9. .vidioc_streamon = vip_streamon, 
  10. .vidioc_streamoff = vip_streamoff, 
  11.  
  12. 、、、、、、 
  13. }; 
static const struct v4l2_ioctl_ops vip_capture_ioctl_fops = {

、、、、、、

 .vidioc_reqbufs  = vip_reqbufs,
 .vidioc_querybuf = vip_querybuf,
 .vidioc_qbuf  = vip_qbuf,
 .vidioc_dqbuf  = vip_dqbuf,
 .vidioc_streamon = vip_streamon,
 .vidioc_streamoff = vip_streamoff,

、、、、、、
};


2、v4l2层设置回掉函数列表

  1. Static struct videobuf_queue_ops vip_video_qops = { 
  2. .buf_setup   = buffer_setbuf, 
  3. .buf_prepare  = buffer_prepare, 
  4. .buf_queue  = buffer_queue, 
  5. .buf_release  = buffer_release, 
Static struct videobuf_queue_ops vip_video_qops = {
 .buf_setup   = buffer_setbuf,
 .buf_prepare  = buffer_prepare,
 .buf_queue  = buffer_queue,
 .buf_release  = buffer_release,
}


三、函数调用关系分析
1、请求视频流缓冲区
/*Request video streaming buffer memory VIDIOC_REABUFS*/
v4l2_vip.c
A、vip_reqbufs

  1. static int vip_reqbufs(struct file *file, void *priv, 
  2.           struct v4l2_requestbuffers *p) 
  3. struct vip_fh *fh = priv; 
  4.  
  5. return (videobuf_reqbufs(&fh->vb_vidq, p)); 
static int vip_reqbufs(struct file *file, void *priv,
          struct v4l2_requestbuffers *p)
{
 struct vip_fh *fh = priv;

 return (videobuf_reqbufs(&fh->vb_vidq, p));
}


Videobuf-core.c
请求缓冲区,主要是给
B、videobuf_reqbufs

  1. int videobuf_reqbufs(struct videobuf_queue *q, struct v4l2_requestbuffers *req) 
  2. unsigned int size, count; 
  3. int retval; 
  4.  
  5. ?略过参数检测? 
  6.   
  7. count = req->count; 
  8. if (count > VIDEO_MAX_FRAME) 
  9.   count = VIDEO_MAX_FRAME; 
  10. size = 0; 
  11. 调用v4l2驱动实现的参数这只函数buffer大小参数 
  12. q->ops->buf_setup(q, &count, &size); 
  13. size = PAGE_ALIGN(size);//和下一页对其 
  14. dprintk(1, "reqbufs: bufs=%d, size=0x%x [%d pages total]\n"
  15.   count, size, (count*size)>>PAGE_SHIFT); 
  16. //分配缓冲区并返回实际分配的缓冲区个数 
  17. retval = __videobuf_mmap_setup(q, count, size, req->memory); 
  18. if (retval < 0) { 
  19.   dprintk(1, "reqbufs: mmap setup returned %d\n", retval); 
  20.   goto done; 
  21. req->count = retval; 
  22. retval = 0; 
  23. 、、、、、、 
int videobuf_reqbufs(struct videobuf_queue *q, struct v4l2_requestbuffers *req)
{
 unsigned int size, count;
 int retval;

 ?略过参数检测?
 
count = req->count;
 if (count > VIDEO_MAX_FRAME)
  count = VIDEO_MAX_FRAME;
 size = 0;
 调用v4l2驱动实现的参数这只函数buffer大小参数
 q->ops->buf_setup(q, &count, &size);
 size = PAGE_ALIGN(size);//和下一页对其
 dprintk(1, "reqbufs: bufs=%d, size=0x%x [%d pages total]\n",
  count, size, (count*size)>>PAGE_SHIFT);
//分配缓冲区并返回实际分配的缓冲区个数
 retval = __videobuf_mmap_setup(q, count, size, req->memory);
 if (retval < 0) {
  dprintk(1, "reqbufs: mmap setup returned %d\n", retval);
  goto done;
 }
 req->count = retval;
 retval = 0;
、、、、、、
}


C、__videobuf_mmap_setup

  1. /* Locking: Caller holds q->vb_lock */ 
  2. int __videobuf_mmap_setup(struct videobuf_queue *q, 
  3.    unsigned int bcount, unsigned int bsize, enum v4l2_memory memory) 
  4. unsigned int i; 
  5. int err; 
  6.  
  7. MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); 
  8. //清空之前用的videobuf缓冲区 
  9. err = __videobuf_mmap_free(q); 
  10. if (0 != err) 
  11.   return err; 
  12.  
  13. /* Allocate and initialize buffers */ 
  14. for (i = 0; i < bcount; i++) { 
  15.   q->bufs[i] = videobuf_alloc(q);//分配bcount个struct videobuf_buffer 
  16.   if (q->bufs[i] == NULL) 
  17.    break
  18. //初始化基本的参数 
  19.   q->bufs[i]->i      = i; 
  20.   q->bufs[i]->input  = UNSET; 
  21.   q->bufs[i]->memory = memory; 
  22.   q->bufs[i]->bsize  = bsize; 
  23.   switch (memory) { 
  24.   case V4L2_MEMORY_MMAP: 
  25.    q->bufs[i]->boff  = bsize * i; 
  26.    break
  27.   case V4L2_MEMORY_USERPTR: 
  28.   case V4L2_MEMORY_OVERLAY: 
  29.    /* nothing */ 
  30.    break
  31.   } 
  32.  
  33. if (!i) 
  34.   return -ENOMEM; 
  35.  
  36. dprintk(1, "mmap setup: %d buffers, %d bytes each\n"
  37.   i, bsize); 
  38.  
  39. return i; 
/* Locking: Caller holds q->vb_lock */
int __videobuf_mmap_setup(struct videobuf_queue *q,
   unsigned int bcount, unsigned int bsize, enum v4l2_memory memory)
{
 unsigned int i;
 int err;

 MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
//清空之前用的videobuf缓冲区
 err = __videobuf_mmap_free(q);
 if (0 != err)
  return err;

 /* Allocate and initialize buffers */
 for (i = 0; i < bcount; i++) {
  q->bufs[i] = videobuf_alloc(q);//分配bcount个struct videobuf_buffer
  if (q->bufs[i] == NULL)
   break;
//初始化基本的参数
  q->bufs[i]->i      = i;
  q->bufs[i]->input  = UNSET;
  q->bufs[i]->memory = memory;
  q->bufs[i]->bsize  = bsize;
  switch (memory) {
  case V4L2_MEMORY_MMAP:
   q->bufs[i]->boff  = bsize * i;
   break;
  case V4L2_MEMORY_USERPTR:
  case V4L2_MEMORY_OVERLAY:
   /* nothing */
   break;
  }
 }

 if (!i)
  return -ENOMEM;

 dprintk(1, "mmap setup: %d buffers, %d bytes each\n",
  i, bsize);

 return i;
}


D、videobuf_alloc

  1. void *videobuf_alloc(struct videobuf_queue *q) 
  2. struct videobuf_buffer *vb; 
  3.  
  4. BUG_ON(q->msize < sizeof(*vb)); 
  5.  
  6. if (!q->int_ops || !q->int_ops->alloc) { 
  7.   printk(KERN_ERR "No specific ops defined!\n"); 
  8.   BUG(); 
  9. vb = q->int_ops->alloc(q->msize); 
  10. if (NULL != vb) { 
  11.   init_waitqueue_head(&vb->done);//初始化videobuf缓冲区中的等待队列 
  12.   vb->magic     = MAGIC_BUFFER; 
  13.  
  14. return vb; 
  15.  
  16. 在videobuf-vmalloc.c中 
  17. /* ---------------------------------------------------------------------
  18. * vmalloc handlers for the generic methods
  19. /* Allocated area consists on 3 parts:
  20. struct video_buffer
  21. struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
  22. struct videobuf_dma_sg_memory
  23. */ 
  24.  
  25.   
void *videobuf_alloc(struct videobuf_queue *q)
{
 struct videobuf_buffer *vb;

 BUG_ON(q->msize < sizeof(*vb));

 if (!q->int_ops || !q->int_ops->alloc) {
  printk(KERN_ERR "No specific ops defined!\n");
  BUG();
 }
 vb = q->int_ops->alloc(q->msize);
 if (NULL != vb) {
  init_waitqueue_head(&vb->done);//初始化videobuf缓冲区中的等待队列
  vb->magic     = MAGIC_BUFFER;
 }

 return vb;
}

在videobuf-vmalloc.c中
/* ---------------------------------------------------------------------
 * vmalloc handlers for the generic methods
/* Allocated area consists on 3 parts:
 struct video_buffer
 struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
 struct videobuf_dma_sg_memory
 */

 


E、__videobuf_alloc
分配缓冲区的内存空间

  1. static void *__videobuf_alloc(size_t size) 
  2. struct videobuf_vmalloc_memory *mem; 
  3. struct videobuf_buffer *vb; 
  4. //给上边两个数据结构分配空间,size是在open()函数中初始化videobuf时传进来的最顶层的包含videobuf_buffer的设备数据结构体的大小,所以该设备结构体的第一个成员就要是videobuf_buffer。 
  5. vb = kzalloc(size+sizeof(*mem),GFP_KERNEL); 
  6.  
  7. //注意vb->priv是硬件视频数据到用户空间的中转缓冲区 
  8. mem = vb->priv = ((char *)vb)+size; 
  9. mem->magic=MAGIC_VMAL_MEM; 
  10.  
  11. dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n"
  12.   __func__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb), mem,(long)sizeof(*mem)); 
  13.  
  14. //返回分配的struct videobuf_buffer结构体指针 
  15. return vb; 
static void *__videobuf_alloc(size_t size)
{
 struct videobuf_vmalloc_memory *mem;
 struct videobuf_buffer *vb;
//给上边两个数据结构分配空间,size是在open()函数中初始化videobuf时传进来的最顶层的包含videobuf_buffer的设备数据结构体的大小,所以该设备结构体的第一个成员就要是videobuf_buffer。
 vb = kzalloc(size+sizeof(*mem),GFP_KERNEL);

//注意vb->priv是硬件视频数据到用户空间的中转缓冲区
 mem = vb->priv = ((char *)vb)+size;
 mem->magic=MAGIC_VMAL_MEM;

 dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
  __func__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb), mem,(long)sizeof(*mem));

//返回分配的struct videobuf_buffer结构体指针
 return vb;
}


2、获取指定缓冲区的属性
应用程序通过VIDIOC_QUERYBUF ioctl()命令获取上边分配的缓冲区的一些属性,一边将其mmap到用户空间。
A、vip_querybuf

  1. static int vip_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) 
  2. struct vip_fh *fh = priv; 
  3.  
  4. return (videobuf_querybuf(&fh->vb_vidq, p)); 
  5.  
  6. B、videobuf_querybuf 
  7. Int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) 
  8. int ret = -EINVAL; 
  9.  
  10. mutex_lock(&q->vb_lock); 
  11. //参数检测 
  12. 、、、、、 
  13.  
  14. //获取指定videobuf_buffer的一些信息,b->index是应用程序传过来的 
  15. videobuf_status(q, b, q->bufs[b->index], q->type); 
  16.  
  17. ret = 0; 
  18. done: 
  19. mutex_unlock(&q->vb_lock); 
  20. return ret; 
static int vip_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
 struct vip_fh *fh = priv;

 return (videobuf_querybuf(&fh->vb_vidq, p));
}

B、videobuf_querybuf
Int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
{
 int ret = -EINVAL;

 mutex_lock(&q->vb_lock);
//参数检测
、、、、、

//获取指定videobuf_buffer的一些信息,b->index是应用程序传过来的
 videobuf_status(q, b, q->bufs[b->index], q->type);

 ret = 0;
done:
 mutex_unlock(&q->vb_lock);
 return ret;
}


C、videobuf_status
把videobuf_buffer数据成员拷贝到v4l2_buffer的数据中

  1. /* Locking: Caller holds q->vb_lock */ 
  2. static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, 
  3.        struct videobuf_buffer *vb, enum v4l2_buf_type type) 
  4. MAGIC_CHECK(vb->magic, MAGIC_BUFFER); 
  5. MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); 
  6.  
  7. b->index    = vb->i; 
  8. b->type     = type; 
  9.  
  10. b->memory   = vb->memory; 
  11. switch (b->memory) { 
  12. case V4L2_MEMORY_MMAP: 
  13.   b->m.offset  = vb->boff; 
  14.   b->length    = vb->bsize; 
  15.   break
  16. case V4L2_MEMORY_USERPTR: 
  17.   b->m.userptr = vb->baddr; 
  18.   b->length    = vb->bsize; 
  19.   break
  20. case V4L2_MEMORY_OVERLAY: 
  21.   b->m.offset  = vb->boff; 
  22.   break
  23.  
  24. b->flags    = 0; 
  25. if (vb->map) 
  26.   b->flags |= V4L2_BUF_FLAG_MAPPED; 
  27.  
  28. switch (vb->state) { 
  29. case VIDEOBUF_PREPARED: 
  30. case VIDEOBUF_QUEUED: 
  31. case VIDEOBUF_ACTIVE: 
  32.   b->flags |= V4L2_BUF_FLAG_QUEUED; 
  33.   break
  34. case VIDEOBUF_DONE: 
  35. case VIDEOBUF_ERROR: 
  36.   b->flags |= V4L2_BUF_FLAG_DONE; 
  37.   break
  38. case VIDEOBUF_NEEDS_INIT: 
  39. case VIDEOBUF_IDLE: 
  40.   /* nothing */ 
  41.   break
  42.  
  43. if (vb->input != UNSET) { 
  44.   b->flags |= V4L2_BUF_FLAG_INPUT; 
  45.   b->input  = vb->input; 
  46.  
  47. b->field     = vb->field; 
  48. b->timestamp = vb->ts; 
  49. b->bytesused = vb->size; 
  50. b->sequence  = vb->field_count >> 1; 
/* Locking: Caller holds q->vb_lock */
static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
       struct videobuf_buffer *vb, enum v4l2_buf_type type)
{
 MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
 MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);

 b->index    = vb->i;
 b->type     = type;

 b->memory   = vb->memory;
 switch (b->memory) {
 case V4L2_MEMORY_MMAP:
  b->m.offset  = vb->boff;
  b->length    = vb->bsize;
  break;
 case V4L2_MEMORY_USERPTR:
  b->m.userptr = vb->baddr;
  b->length    = vb->bsize;
  break;
 case V4L2_MEMORY_OVERLAY:
  b->m.offset  = vb->boff;
  break;
 }

 b->flags    = 0;
 if (vb->map)
  b->flags |= V4L2_BUF_FLAG_MAPPED;

 switch (vb->state) {
 case VIDEOBUF_PREPARED:
 case VIDEOBUF_QUEUED:
 case VIDEOBUF_ACTIVE:
  b->flags |= V4L2_BUF_FLAG_QUEUED;
  break;
 case VIDEOBUF_DONE:
 case VIDEOBUF_ERROR:
  b->flags |= V4L2_BUF_FLAG_DONE;
  break;
 case VIDEOBUF_NEEDS_INIT:
 case VIDEOBUF_IDLE:
  /* nothing */
  break;
 }

 if (vb->input != UNSET) {
  b->flags |= V4L2_BUF_FLAG_INPUT;
  b->input  = vb->input;
 }

 b->field     = vb->field;
 b->timestamp = vb->ts;
 b->bytesused = vb->size;
 b->sequence  = vb->field_count >> 1;
}


上边函数是应用程序调用获取之前分配video buffer的长度和偏移量,用来应用程序映射该buffer到用户空间

3、将申请的缓冲区放到视频采集输入/输出队列
A、vip_qbuf

  1. /* Queue video memory buffer VIDIOC_QBUF*/ 
  2. static int vip_qbuf(struct file *file, viod *priv, struct v4l2_buffer *p) 
  3. struct vip_fh *fh = priv; 
  4. return (videobuf_qbuf(&fh->vb_vidq, p)); 
/* Queue video memory buffer VIDIOC_QBUF*/
static int vip_qbuf(struct file *file, viod *priv, struct v4l2_buffer *p)
{
 struct vip_fh *fh = priv;
 return (videobuf_qbuf(&fh->vb_vidq, p));
}


B、videobuf_qbuf
//每一个分配的缓冲区都要执行这个函数

  1. int videobuf_qbuf(struct videobuf_queue *q, 
  2.        struct v4l2_buffer *b) 
  3. struct videobuf_buffer *buf; 
  4. enum v4l2_field field; 
  5. unsigned long flags = 0; 
  6. int retval; 
  7.  
  8. MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); 
  9. //略过加锁,参数以及运行状态检测 
  10. 、、、、、、、、、、、、、、、、、 
  11. buf = q->bufs[b->index];//index由应用程序指定 
  12.   
  13. switch (b->memory) { 
  14. case V4L2_MEMORY_MMAP: 
  15.   if (0 == buf->baddr) { 
  16.    dprintk(1, "qbuf: mmap requested " 
  17.        "but buffer addr is zero!\n"); 
  18.    goto done; 
  19.   } 
  20.   break
  21. case V4L2_MEMORY_USERPTR: 
  22.   if (b->length < buf->bsize) { 
  23.    dprintk(1, "qbuf: buffer length is not enough\n"); 
  24.    goto done; 
  25.   } 
  26.   if (VIDEOBUF_NEEDS_INIT != buf->state && 
  27.       buf->baddr != b->m.userptr) 
  28.    q->ops->buf_release(q, buf); 
  29.   buf->baddr = b->m.userptr; 
  30.   break
  31. case V4L2_MEMORY_OVERLAY: 
  32.   buf->boff = b->m.offset; 
  33.   break
  34. default
  35.   dprintk(1, "qbuf: wrong memory type\n"); 
  36.   goto done; 
  37.  
  38. dprintk(1, "qbuf: requesting next field\n"); 
  39. field = videobuf_next_field(q);//根据当前的场,得到下一个场域 
  40. retval = q->ops->buf_prepare(q, buf, field);//设置缓冲区的参数 
  41. if (0 != retval) { 
  42.   dprintk(1, "qbuf: buffer_prepare returned %d\n", retval); 
  43.   goto done; 
  44.  
  45. list_add_tail(&buf->stream, &q->stream);//将该缓冲区添加到输出队列中 
  46. if (q->streaming) { 
  47.   spin_lock_irqsave(q->irqlock, flags); 
  48.   q->ops->buf_queue(q, buf); 
  49.   spin_unlock_irqrestore(q->irqlock, flags); 
  50. dprintk(1, "qbuf: succeded\n"); 
  51. retval = 0; 
  52. wake_up_interruptible_sync(&q->wait); 
  53.  
  54. done: 
  55. mutex_unlock(&q->vb_lock); 
  56.  
  57. if (b->memory == V4L2_MEMORY_MMAP) 
  58.   up_read(¤t->mm->mmap_sem); 
  59.  
  60. return retval; 
int videobuf_qbuf(struct videobuf_queue *q,
       struct v4l2_buffer *b)
{
 struct videobuf_buffer *buf;
 enum v4l2_field field;
 unsigned long flags = 0;
 int retval;

 MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
//略过加锁,参数以及运行状态检测
、、、、、、、、、、、、、、、、、
 buf = q->bufs[b->index];//index由应用程序指定
 
 switch (b->memory) {
 case V4L2_MEMORY_MMAP:
  if (0 == buf->baddr) {
   dprintk(1, "qbuf: mmap requested "
       "but buffer addr is zero!\n");
   goto done;
  }
  break;
 case V4L2_MEMORY_USERPTR:
  if (b->length < buf->bsize) {
   dprintk(1, "qbuf: buffer length is not enough\n");
   goto done;
  }
  if (VIDEOBUF_NEEDS_INIT != buf->state &&
      buf->baddr != b->m.userptr)
   q->ops->buf_release(q, buf);
  buf->baddr = b->m.userptr;
  break;
 case V4L2_MEMORY_OVERLAY:
  buf->boff = b->m.offset;
  break;
 default:
  dprintk(1, "qbuf: wrong memory type\n");
  goto done;
 }

 dprintk(1, "qbuf: requesting next field\n");
 field = videobuf_next_field(q);//根据当前的场,得到下一个场域
 retval = q->ops->buf_prepare(q, buf, field);//设置缓冲区的参数
 if (0 != retval) {
  dprintk(1, "qbuf: buffer_prepare returned %d\n", retval);
  goto done;
 }

 list_add_tail(&buf->stream, &q->stream);//将该缓冲区添加到输出队列中
 if (q->streaming) {
  spin_lock_irqsave(q->irqlock, flags);
  q->ops->buf_queue(q, buf);
  spin_unlock_irqrestore(q->irqlock, flags);
 }
 dprintk(1, "qbuf: succeded\n");
 retval = 0;
 wake_up_interruptible_sync(&q->wait);

 done:
 mutex_unlock(&q->vb_lock);

 if (b->memory == V4L2_MEMORY_MMAP)
  up_read(¤t->mm->mmap_sem);

 return retval;
}




4、从输出队列取出已含有采集数据的帧缓冲区
A、vip_dqbuf

  1. /*Transfer buffers beween incoming and outgoing queue VIDIOC_DQBUF*/ 
  2. static int vip_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) 
  3. struct vip_fh *fh = priv; 
  4. return (videobuf_dqbuf(&fh->vb_vidq, p, file->f_flags & O_NONBLOCK)); 
/*Transfer buffers beween incoming and outgoing queue VIDIOC_DQBUF*/
static int vip_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{
 struct vip_fh *fh = priv;
 return (videobuf_dqbuf(&fh->vb_vidq, p, file->f_flags & O_NONBLOCK));
}


B、videobuf_dqbuf

  1. int videobuf_dqbuf(struct videobuf_queue *q, 
  2.         struct v4l2_buffer *b, int nonblocking) 
  3. struct videobuf_buffer *buf = NULL; 
  4. int retval; 
  5.  
  6. MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); 
  7.  
  8. mutex_lock(&q->vb_lock); 
  9.  
  10. //获取下一个已近填充视频数据的缓冲区 
  11. retval = stream_next_buffer(q, &buf, nonblocking); 
  12. if (retval < 0) { 
  13.   dprintk(1, "dqbuf: next_buffer error: %i\n", retval); 
  14.   goto done; 
  15. //略过buf->state处理 
  16. 、、、、、、 
  17. list_del(&buf->stream);//将该缓冲区从链表中删除,使其处于用户状态 
  18. memset(b, 0, sizeof(*b)); 
  19. videobuf_status(q, b, buf, q->type); 
  20.  
  21. done: 
  22. mutex_unlock(&q->vb_lock); 
  23. return retval; 
int videobuf_dqbuf(struct videobuf_queue *q,
        struct v4l2_buffer *b, int nonblocking)
{
 struct videobuf_buffer *buf = NULL;
 int retval;

 MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);

 mutex_lock(&q->vb_lock);

//获取下一个已近填充视频数据的缓冲区
 retval = stream_next_buffer(q, &buf, nonblocking);
 if (retval < 0) {
  dprintk(1, "dqbuf: next_buffer error: %i\n", retval);
  goto done;
 }
//略过buf->state处理
、、、、、、
 }
 list_del(&buf->stream);//将该缓冲区从链表中删除,使其处于用户状态
 memset(b, 0, sizeof(*b));
 videobuf_status(q, b, buf, q->type);

 done:
 mutex_unlock(&q->vb_lock);
 return retval;
}


C、stream_next_buffer
如果输出队列中有视频数据的缓冲区,并且缓冲区的状态正常,那么就返回该缓冲区

  1. /* Locking: Caller holds q->vb_lock */ 
  2. static int stream_next_buffer(struct videobuf_queue *q, 
  3.    struct videobuf_buffer **vb, int nonblocking) 
  4. int retval; 
  5. struct videobuf_buffer *buf = NULL; 
  6.  
  7. retval = stream_next_buffer_check_queue(q, nonblocking); 
  8. if (retval) 
  9.   goto done; 
  10.   
  11. //得到输出队列中第一个有视频数据的缓冲区 
  12. buf = list_entry(q->stream.next, struct videobuf_buffer, stream); 
  13. retval = videobuf_waiton(buf, nonblocking, 1); 
  14. if (retval < 0) 
  15.   goto done; 
  16.  
  17. *vb = buf;//正常返回该缓冲区 
  18. done: 
  19. return retval; 
/* Locking: Caller holds q->vb_lock */
static int stream_next_buffer(struct videobuf_queue *q,
   struct videobuf_buffer **vb, int nonblocking)
{
 int retval;
 struct videobuf_buffer *buf = NULL;

 retval = stream_next_buffer_check_queue(q, nonblocking);
 if (retval)
  goto done;
 
//得到输出队列中第一个有视频数据的缓冲区
 buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
 retval = videobuf_waiton(buf, nonblocking, 1);
 if (retval < 0)
  goto done;

 *vb = buf;//正常返回该缓冲区
done:
 return retval;
}


D、stream_next_buffer_check_queue
这个函数的功能就是检测是否开始队列中视频数据流的传输(q->streaming),如果没有,就返回负的错误吗。如果开始传输,再判断输出队列中是否有缓冲区,有的话正常返回0,否则根据阻塞标志看是返回错误码还是阻塞等待输出队列缓冲区。

  1. /* Locking: Caller holds q->vb_lock */ 
  2. static int stream_next_buffer_check_queue(struct videobuf_queue *q, int noblock) 
  3. int retval; 
  4.  
  5. checks: 
  6. if (!q->streaming) {//在stream on中置位1,意味着开始流数据传输 
  7.   dprintk(1, "next_buffer: Not streaming\n"); 
  8.   retval = -EINVAL; 
  9.   goto done; 
  10.  
  11. if (list_empty(&q->stream)) {//如果输出队列为空,则根据传入的阻塞标志看是否要等待 
  12.   if (noblock) {//如果是非阻塞的流处理,则直接返回 
  13.    retval = -EAGAIN; 
  14.    dprintk(2, "next_buffer: no buffers to dequeue\n"); 
  15.    goto done; 
  16.   } else {//如果是阻塞流处理,则是当前读取数据进程进入等待状态,当输出队列有缓冲区时唤醒该进程。 
  17.    dprintk(2, "next_buffer: waiting on buffer\n"); 
  18.  
  19.    /* Drop lock to avoid deadlock with qbuf */ 
  20.    mutex_unlock(&q->vb_lock); 
  21.  
  22. /* Checking list_empty and streaming is safe without locks because we goto checks to validate while  holding locks before proceeding */ 
  23. retval= 
  24. wait_event_interruptible(q->wait,!list_empty(&q->stream)|| !q->streaming); 
  25.    mutex_lock(&q->vb_lock); 
  26.  
  27.    if (retval) 
  28.     goto done; 
  29.  
  30.    goto checks; 
  31.   } 
  32. retval = 0; 
  33. done: 
  34. return retval; 
/* Locking: Caller holds q->vb_lock */
static int stream_next_buffer_check_queue(struct videobuf_queue *q, int noblock)
{
 int retval;

checks:
 if (!q->streaming) {//在stream on中置位1,意味着开始流数据传输
  dprintk(1, "next_buffer: Not streaming\n");
  retval = -EINVAL;
  goto done;
 }

 if (list_empty(&q->stream)) {//如果输出队列为空,则根据传入的阻塞标志看是否要等待
  if (noblock) {//如果是非阻塞的流处理,则直接返回
   retval = -EAGAIN;
   dprintk(2, "next_buffer: no buffers to dequeue\n");
   goto done;
  } else {//如果是阻塞流处理,则是当前读取数据进程进入等待状态,当输出队列有缓冲区时唤醒该进程。
   dprintk(2, "next_buffer: waiting on buffer\n");

   /* Drop lock to avoid deadlock with qbuf */
   mutex_unlock(&q->vb_lock);

/* Checking list_empty and streaming is safe without locks because we goto checks to validate while  holding locks before proceeding */
retval=
wait_event_interruptible(q->wait,!list_empty(&q->stream)|| !q->streaming);
   mutex_lock(&q->vb_lock);

   if (retval)
    goto done;

   goto checks;
  }
 }
 retval = 0;
done:
 return retval;
}



该函数用来判断视频缓冲区的状态是否在队列和激活,否则等待
E、videobuf_waiton

  1. #define WAITON_CONDITION (vb->state != VIDEOBUF_ACTIVE && vb->state != VIDEOBUF_QUEUED) 
  2. int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr) 
  3. MAGIC_CHECK(vb->magic, MAGIC_BUFFER); 
  4.  
  5. if (non_blocking) {//如果是非阻塞流操作操作 
  6.   if (WAITON_CONDITION)//并且等待条件满足 
  7.    return 0;//则正常返回 
  8.   else 
  9.    return -EAGAIN;//否则返回错误码 
  10. //如果是阻塞流操作,那么就会使该进程进入等待队列 
  11. if (intr) 
  12.   return wait_event_interruptible(vb->done, WAITON_CONDITION); 
  13. else 
  14.   wait_event(vb->done, WAITON_CONDITION); 
  15.  
  16. return 0; 
#define WAITON_CONDITION (vb->state != VIDEOBUF_ACTIVE && vb->state != VIDEOBUF_QUEUED)
int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr)
{
 MAGIC_CHECK(vb->magic, MAGIC_BUFFER);

 if (non_blocking) {//如果是非阻塞流操作操作
  if (WAITON_CONDITION)//并且等待条件满足
   return 0;//则正常返回
  else
   return -EAGAIN;//否则返回错误码
 }
//如果是阻塞流操作,那么就会使该进程进入等待队列
 if (intr)
  return wait_event_interruptible(vb->done, WAITON_CONDITION);
 else
  wait_event(vb->done, WAITON_CONDITION);

 return 0;
}



四、V4L2 层缓冲区参数设置:
1、buffer_setup

  1. static int buffer_setup(struct video_queue *vp, unsigned *count, 
  2.             unsigned int *size) 
  3. struct vip_fh    *fh = vq->priv_data; 
  4. struct vip_dev  *dev = fh->dev; 
  5.  
  6. *size = fh->width*fh->height*2;//两场odd/even 
  7.  
  8. if(0 == *count) 
  9.   *count = 32; 
  10. while(*size * *count > vid_limit * 1024 *1024);//最大缓冲区限制 
  11.   (*count)--; 
  12.  
  13. dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__, *count, *size); 
  14. return 0; 
static int buffer_setup(struct video_queue *vp, unsigned *count,
            unsigned int *size)
{
 struct vip_fh    *fh = vq->priv_data;
 struct vip_dev  *dev = fh->dev;

 *size = fh->width*fh->height*2;//两场odd/even

 if(0 == *count)
  *count = 32;
 while(*size * *count > vid_limit * 1024 *1024);//最大缓冲区限制
  (*count)--;

 dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__, *count, *size);
 return 0;
}


2、buffer_prepare

  1. static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, 
  2.        rnum v4l2_field field) 
  3. struct vip_fh *fh = vq->priv_data;/*open set*/ 
  4. struct vip_dev *dev = fh->dev; 
  5. struct vip_buffer *buf = container_of(vb, struct vip_buffer, vb); 
  6. int rc; 
  7.  
  8. dprintk(dev, 1, "%s, field=%d\n", __func__, field); 
  9.  
  10. BUG_ON(NULL == fh->fmt); 
  11.  
  12. if(fh->width < NORM_MINW || fh->width > NORM_MAXW || 
  13.   fh->height < NORM_MINH || fh->height > NORM_MAXH) 
  14.    return -EINVAL; 
  15.  
  16. buf->vb.size = fh->width * fh->height * 2; 
  17. if(0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) 
  18.   return -EINVAL; 
  19.  
  20. //设置缓冲区的像素参数 
  21. buf->fmt   = fh->fmt; 
  22. buf->vb.width  = fh->width; 
  23. buf->vb.heignt  = fh->heignt; 
  24. buf->vb.filed  = fh->filed; 
  25.  
  26. //precalculate_bars(fh); 
  27.  
  28. if(VIDEOBUF_NEEDS_INIT == buf->vb.state){ 
  29.   rc = videobuf_iolock(vq, &buf->vb, NULL); 
  30.   if(rc < 0) 
  31.    goto fail; 
  32. buf->vb.state = VIDEOBUF_PREPARED; 
  33. return 0; 
  34.  
  35. fail: 
  36. free_buffer(vq, buf); 
  37. return rc; 
static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
       rnum v4l2_field field)
{
 struct vip_fh *fh = vq->priv_data;/*open set*/
 struct vip_dev *dev = fh->dev;
 struct vip_buffer *buf = container_of(vb, struct vip_buffer, vb);
 int rc;

 dprintk(dev, 1, "%s, field=%d\n", __func__, field);

 BUG_ON(NULL == fh->fmt);

 if(fh->width < NORM_MINW || fh->width > NORM_MAXW ||
  fh->height < NORM_MINH || fh->height > NORM_MAXH)
   return -EINVAL;

 buf->vb.size = fh->width * fh->height * 2;
 if(0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
  return -EINVAL;

 //设置缓冲区的像素参数
 buf->fmt   = fh->fmt;
 buf->vb.width  = fh->width;
 buf->vb.heignt  = fh->heignt;
 buf->vb.filed  = fh->filed;

 //precalculate_bars(fh);

 if(VIDEOBUF_NEEDS_INIT == buf->vb.state){
  rc = videobuf_iolock(vq, &buf->vb, NULL);
  if(rc < 0)
   goto fail;
 }
 buf->vb.state = VIDEOBUF_PREPARED;
 return 0;

fail:
 free_buffer(vq, buf);
 return rc;
}


3、buffer_queue

  1. static void buffer_queue (struct videobuf_queue *vq, struct videobuf_buffer *vb) 
  2. struct vip_buffer  *buf  = container(vb, struct vip_buffer, vb); 
  3. struct vip_fh   *fh   = vq->priv_data; 
  4. struct vip_dev   *dev  = fh->dev; 
  5. struct vip_damqueue  *vdq  = &dev->vidq; 
  6.  
  7. dprintk(dev, 1, "%s\n, __func__"); 
  8.  
  9. buf->vb.state = VIDEOBUF_QUEUED; 
  10. list_add_tail(&buf->vb.queue, &vdq->active);//添加缓冲区到DMA链表 
static void buffer_queue (struct videobuf_queue *vq, struct videobuf_buffer *vb)
{
 struct vip_buffer  *buf  = container(vb, struct vip_buffer, vb);
 struct vip_fh   *fh   = vq->priv_data;
 struct vip_dev   *dev  = fh->dev;
 struct vip_damqueue  *vdq  = &dev->vidq;

 dprintk(dev, 1, "%s\n, __func__");

 buf->vb.state = VIDEOBUF_QUEUED;
 list_add_tail(&buf->vb.queue, &vdq->active);//添加缓冲区到DMA链表
}


  1. enum videobuf_state{ 
  2. VIDEOBUF_DEDDS_INIT = 0   realse_buffer() 
  3. VIDEOBUF_PREPARED  = 1   buffer_prepare() 
  4. VIDEOBUF_QUEUE  = 2   buffer_queue() 
  5. VIDEOBUF_ACTIVE  = 3 
  6. VIDEOBUF_DONE   = 4   fillbuff()->wake_up(&buf->vb.done) 
  7. VIDEOBUF_ERROR  = 5 
  8. VIDEOBUF_IDLE   = 6 
  9. 应用程序的调用过程: 
  10. 1、 reqbufs() -> buf_setup() 
  11.  
  12. 2、 querybuf()->videobuf_status() 
  13.  
  14. 3、 qbuf()->buf_prepare() 
  15.  
  16. 4、 streamon()->buf_queue() 
  17. wake_up_interruptible_sysc(&q->wait) 
  18.  
  19. 5、 dqbuf()->stream_next_buffer()->stream_next_buffer_check_queue() 
  20.  
  21. 6、 qbuf()->buf_prepare()->buf_queue() 
  22.  
  23.   
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值