Videobuf 流程


videobuf是應用程式和v4l2驅動程式的一個中間層,用它來進行視訊資料緩衝區的分配和管理。

它根據應用程式的需求(緩衝區的數量的大小),分配相應的視訊緩衝區,這個緩衝區是在內核空間分配的,並通過mmap方法映射到用戶空間,在內核空間形成 一個緩衝區佇列,在應用程式中有相應的緩衝區陣列對應,它們指向的記憶體位址是一樣的。在驅動程式中,根據配置的硬體參數(FIFO閾值),將vip硬體圖 像記憶體中的資料放到緩衝區佇列中的 每個緩衝區,然後等待應用程式來讀取該緩衝區的資料。videobuf主要由一些特殊的資料結構和ioctl呼叫組成,下邊對其做整體分析:

一、 初始化

初始化緩衝區佇列:
1、驅動層的呼叫
v4l2_vip.c文件中:

  1. static int vip_open(struct file *file)  
  2. {  
  3.  struct vip_dev *dev = video_drvdata(file);  
  4.  struct vip_fh *fh = NULL;  
  5.  int retval = 0;  
  6.   
  7. 、、、、、、、、、  
  8.   
  9.  /*allocate and initialize per filehandle data*/  
  10.  fh = kzalloc(sizeof(*fh), GFP_KERNEL);//此時已經把vb_vidq成員的空間分配好  
  11.  if(NULL == fh){  
  12.   dev->users--;  
  13.   retval = -ENOMEM;  
  14.  }  
  15.   
  16. 、、、、、、、、、、  
  17.   
  18.  fh->type    = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  19.  fh->fmt    = &formats[0];  
  20.   
  21. 、、、、、、、、  
  22.   
  23.  /*初始化videobuf緩衝區佇列 vip_video_qops 是驅動層的videobuf回掉函數*/  
  24.  videobuf_queue_vmalloc_init(&fh->vb_vidq, &vip_video_qops, NULL,  
  25.      &dev->slock, fh->type,  V4L2_FIELD_INTERLACED,  
  26.      sizeof(struct vip_buffer), fh);  
  27.  return 0;  
  28. }  


2videobuf層的操作
videobuf-vmalloc.c中:

  1. videobuf_queue_vmalloc_initstruct 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. {  
  11.  videobuf_queue_core_initq, ops, dev, irlock, type, field, msize, priv, &qops);  
  12. }  
  13.   
  14. //上邊函數多了一個qops參數,它是 videobuf層的資料操作函數集  
  15. void videobuf_queue_core_init(struct videobuf_queue *q,  
  16.     struct videobuf_queue_ops *ops,  
  17.     struct device *dev,  
  18.     spinlock_t *irqlock,  
  19.     enum v4l2_buf_type type,  
  20.     enum v4l2_field field,  
  21.     unsigned int msize,  
  22.     void *priv,  
  23.     struct videobuf_qtype_ops *int_ops)  
  24. {  
  25.  BUG_ON(!q);  
  26.  memset(q, 0, sizeof(*q));  
  27. //初始化佇列的一些成員  
  28.  q->irqlock   = irqlock;  
  29.  q->dev       = dev;  
  30.  q->type      = type;  
  31.  q->field     = field;  
  32.  q->msize     = msize;  
  33.  q->ops       = ops;  
  34.  q->priv_data = priv;  
  35.  q->int_ops   = int_ops;  
  36.   
  37. //檢測必要的成員資料是否不為空  
  38.  /* All buffer operations are mandatory */  
  39.  BUG_ON(!q->ops->buf_setup);  
  40.  BUG_ON(!q->ops->buf_prepare);  
  41.  BUG_ON(!q->ops->buf_queue);  
  42.  BUG_ON(!q->ops->buf_release);  
  43.   
  44.  /* Lock is mandatory for queue_cancel to work */  
  45.  BUG_ON(!irqlock);  
  46.   
  47.  /* Having implementations for abstract methods are mandatory */  
  48.  BUG_ON(!q->int_ops);  
  49.   
  50.  mutex_init(&q->vb_lock);//初始化自旋鎖  
  51.  init_waitqueue_head(&q->wait);//初始化videobuf佇列queue中的等待佇列  
  52.  INIT_LIST_HEAD(&q->stream);//初始化鏈表  
  53. }  


二、 videobuf的相關ioctl()操作
這些操作有三部分組成,1是應用程式通過ioctl函式呼叫v4l2驅動中實現的介面函數,2這些介面函數在呼叫videobuf層的回應函數來做出處理,3如果有的處理參數需要v4l2層來決定的話,就呼叫v4l2層的videobuf設置函數。

1ioctl介面函數清單

  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. };  


2v4l2層設置回掉函數清單

[cpp] view plaincopy

  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,  
  6. }  


三、函式呼叫關係分析
1、請求視訊流緩衝區
/*Request video streaming buffer memory VIDIOC_REABUFS*/
v4l2_vip.c

Avip_reqbufs

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


Videobuf-core.c
請求緩衝區,主要是給
Bvideobuf_reqbufs

  1. int videobuf_reqbufs(struct videobuf_queue *q, struct v4l2_requestbuffers *req)  
  2. {  
  3.  unsigned int size, count;  
  4.  int retval;  
  5.   
  6.  ?略過參數檢測?  
  7.    
  8. count = req->count;  
  9.  if (count > VIDEO_MAX_FRAME)  
  10.   count = VIDEO_MAX_FRAME;  
  11.  size = 0;  
  12.  呼叫v4l2驅動實現的參數這只函數buffer大小參數  
  13.  q->ops->buf_setup(q, &count, &size);  
  14.  size = PAGE_ALIGN(size);//和下一頁對其  
  15.  dprintk(1, "reqbufs: bufs=%d, size=0x%x [%d pages total]\n",  
  16.   count, size, (count*size)>>PAGE_SHIFT);  
  17. //分配緩衝區並返回實際分配的緩衝區個數  
  18.  retval = __videobuf_mmap_setup(q, count, size, req->memory);  
  19.  if (retval < 0) {  
  20.   dprintk(1, "reqbufs: mmap setup returned %d\n", retval);  
  21.   goto done;  
  22.  }  
  23.  req->count = retval;  
  24.  retval = 0;  
  25. 、、、、、、  
  26. }  


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. {  
  5.  unsigned int i;  
  6.  int err;  
  7.   
  8.  MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);  
  9. //清空之前用的videobuf緩衝區  
  10.  err = __videobuf_mmap_free(q);  
  11.  if (0 != err)  
  12.   return err;  
  13.   
  14.  /* Allocate and initialize buffers */  
  15.  for (i = 0; i < bcount; i++) {  
  16.   q->bufs[i] = videobuf_alloc(q);//分配bcountstruct videobuf_buffer  
  17.   if (q->bufs[i] == NULL)  
  18.    break;  
  19. //初始化基本的參數  
  20.   q->bufs[i]->i      = i;  
  21.   q->bufs[i]->input  = UNSET;  
  22.   q->bufs[i]->memory = memory;  
  23.   q->bufs[i]->bsize  = bsize;  
  24.   switch (memory) {  
  25.   case V4L2_MEMORY_MMAP:  
  26.    q->bufs[i]->boff  = bsize * i;  
  27.    break;  
  28.   case V4L2_MEMORY_USERPTR:  
  29.   case V4L2_MEMORY_OVERLAY:  
  30.    /* nothing */  
  31.    break;  
  32.   }  
  33.  }  
  34.   
  35.  if (!i)  
  36.   return -ENOMEM;  
  37.   
  38.  dprintk(1, "mmap setup: %d buffers, %d bytes each\n",  
  39.   i, bsize);  
  40.   
  41.  return i;  
  42. }  


Dvideobuf_alloc

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


E__videobuf_alloc
分配緩衝區的記憶體空間

  1. static void *__videobuf_alloc(size_t size)  
  2. {  
  3.  struct videobuf_vmalloc_memory *mem;  
  4.  struct videobuf_buffer *vb;  
  5. //給上邊兩個資料結構分配空間,size是在open()函數中初始化videobuf時傳進來的最頂層的包含videobuf_buffer的設備資料結構體的大小,所以該設備結構體的第一個成員就要是videobuf_buffer  
  6.  vb = kzalloc(size+sizeof(*mem),GFP_KERNEL);  
  7.   
  8. //注意vb->priv是硬體視訊資料到使用者空間的中轉緩衝區  
  9.  mem = vb->priv = ((char *)vb)+size;  
  10.  mem->magic=MAGIC_VMAL_MEM;  
  11.   
  12.  dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",  
  13.   __func__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb), mem,(long)sizeof(*mem));  
  14.   
  15. //返回分配的struct videobuf_buffer結構體指標  
  16.  return vb;  
  17. }  


2、獲取指定緩衝區的屬性
應用程式通過VIDIOC_QUERYBUF ioctl()命令獲取上邊分配的緩衝區的一些屬性,一邊將其mmap到用戶空間。
Avip_querybuf

  1. static int vip_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)  
  2. {  
  3.  struct vip_fh *fh = priv;  
  4.   
  5.  return (videobuf_querybuf(&fh->vb_vidq, p));  
  6. }  
  7.   
  8. Bvideobuf_querybuf  
  9. Int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)  
  10. {  
  11.  int ret = -EINVAL;  
  12.   
  13.  mutex_lock(&q->vb_lock);  
  14. //參數檢測  
  15. 、、、、、  
  16.   
  17. //獲取指定videobuf_buffer的一些資訊,b->index是應用程式傳過來的  
  18.  videobuf_status(q, b, q->bufs[b->index], q->type);  
  19.   
  20.  ret = 0;  
  21. done:  
  22.  mutex_unlock(&q->vb_lock);  
  23.  return ret;  
  24. }  


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


上邊函數是應用程式呼叫獲取之前分配video buffer的長度和偏移量,用來應用程式映射該buffer到使用者空間

3、將申請的緩衝區放到視訊採集輸入/輸出佇列 
Avip_qbuf

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


Bvideobuf_qbuf
//每一個分配的緩衝區都要執行這個函數

  1. int videobuf_qbuf(struct videobuf_queue *q,  
  2.        struct v4l2_buffer *b)  
  3. {  
  4.  struct videobuf_buffer *buf;  
  5.  enum v4l2_field field;  
  6.  unsigned long flags = 0;  
  7.  int retval;  
  8.   
  9.  MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);  
  10. //略過加鎖,參數以及運行狀態檢測  
  11. 、、、、、、、、、、、、、、、、、  
  12.  buf = q->bufs[b->index];//index由應用程式指定  
  13.    
  14.  switch (b->memory) {  
  15.  case V4L2_MEMORY_MMAP:  
  16.   if (0 == buf->baddr) {  
  17.    dprintk(1, "qbuf: mmap requested "  
  18.        "but buffer addr is zero!\n");  
  19.    goto done;  
  20.   }  
  21.   break;  
  22.  case V4L2_MEMORY_USERPTR:  
  23.   if (b->length < buf->bsize) {  
  24.    dprintk(1, "qbuf: buffer length is not enough\n");  
  25.    goto done;  
  26.   }  
  27.   if (VIDEOBUF_NEEDS_INIT != buf->state &&  
  28.       buf->baddr != b->m.userptr)  
  29.    q->ops->buf_release(q, buf);  
  30.   buf->baddr = b->m.userptr;  
  31.   break;  
  32.  case V4L2_MEMORY_OVERLAY:  
  33.   buf->boff = b->m.offset;  
  34.   break;  
  35.  default:  
  36.   dprintk(1, "qbuf: wrong memory type\n");  
  37.   goto done;  
  38.  }  
  39.   
  40.  dprintk(1, "qbuf: requesting next field\n");  
  41.  field = videobuf_next_field(q);//根據當前的場,得到下一個場域  
  42.  retval = q->ops->buf_prepare(q, buf, field);//設置緩衝區的參數  
  43.  if (0 != retval) {  
  44.   dprintk(1, "qbuf: buffer_prepare returned %d\n", retval);  
  45.   goto done;  
  46.  }  
  47.   
  48.  list_add_tail(&buf->stream, &q->stream);//將該緩衝區添加到輸出佇列中  
  49.  if (q->streaming) {  
  50.   spin_lock_irqsave(q->irqlock, flags);  
  51.   q->ops->buf_queue(q, buf);  
  52.   spin_unlock_irqrestore(q->irqlock, flags);  
  53.  }  
  54.  dprintk(1, "qbuf: succeded\n");  
  55.  retval = 0;  
  56.  wake_up_interruptible_sync(&q->wait);  
  57.   
  58.  done:  
  59.  mutex_unlock(&q->vb_lock);  
  60.   
  61.  if (b->memory == V4L2_MEMORY_MMAP)  
  62.   up_read(¤t->mm->mmap_sem);  
  63.   
  64.  return retval;  
  65. }  


4、從輸出佇列取出已含有採集資料的框架緩衝區
Avip_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. {  
  4.  struct vip_fh *fh = priv;  
  5.  return (videobuf_dqbuf(&fh->vb_vidq, p, file->f_flags & O_NONBLOCK));  
  6. }  


Bvideobuf_dqbuf

  1. int videobuf_dqbuf(struct videobuf_queue *q,  
  2.         struct v4l2_buffer *b, int nonblocking)  
  3. {  
  4.  struct videobuf_buffer *buf = NULL;  
  5.  int retval;  
  6.   
  7.  MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);  
  8.   
  9.  mutex_lock(&q->vb_lock);  
  10.   
  11. //獲取下一個已近填充視訊資料的緩衝區  
  12.  retval = stream_next_buffer(q, &buf, nonblocking);  
  13.  if (retval < 0) {  
  14.   dprintk(1, "dqbuf: next_buffer error: %i\n", retval);  
  15.   goto done;  
  16.  }  
  17. //略過buf->state處理  
  18. 、、、、、、  
  19.  }  
  20.  list_del(&buf->stream);//將該緩衝區從鏈表中刪除,使其處於使用者狀態  
  21.  memset(b, 0, sizeof(*b));  
  22.  videobuf_status(q, b, buf, q->type);  
  23.   
  24.  done:  
  25.  mutex_unlock(&q->vb_lock);  
  26.  return retval;  
  27. }  


Cstream_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. {  
  5.  int retval;  
  6.  struct videobuf_buffer *buf = NULL;  
  7.   
  8.  retval = stream_next_buffer_check_queue(q, nonblocking);  
  9.  if (retval)  
  10.   goto done;  
  11.    
  12. //得到輸出佇列中第一個有視訊資料的緩衝區  
  13.  buf = list_entry(q->stream.next, struct videobuf_buffer, stream);  
  14.  retval = videobuf_waiton(buf, nonblocking, 1);  
  15.  if (retval < 0)  
  16.   goto done;  
  17.   
  18.  *vb = buf;//正常返回該緩衝區  
  19. done:  
  20.  return retval;  
  21. }  


Dstream_next_buffer_check_queue
這個函數的功能就是檢測是否開始佇列中視訊資料流程的傳輸(q->streaming),如果沒有,就返回負的錯誤嗎。如果開始傳輸,再判斷輸出佇列中是否有緩衝區,有的話正常返回0,否則根據阻塞標誌看是返回錯誤碼還是阻塞等待輸出佇列緩衝區。

[cpp] view plaincopy

  1. /* Locking: Caller holds q->vb_lock */  
  2. static int stream_next_buffer_check_queue(struct videobuf_queue *q, int noblock)  
  3. {  
  4.  int retval;  
  5.   
  6. checks:  
  7.  if (!q->streaming) {//stream on中置位1,意味著開始流資料傳輸  
  8.   dprintk(1, "next_buffer: Not streaming\n");  
  9.   retval = -EINVAL;  
  10.   goto done;  
  11.  }  
  12.   
  13.  if (list_empty(&q->stream)) {//如果輸出佇列為空,則根據傳入的阻塞標誌看是否要等待  
  14.   if (noblock) {//如果是非阻塞的流處理,則直接返回  
  15.    retval = -EAGAIN;  
  16.    dprintk(2, "next_buffer: no buffers to dequeue\n");  
  17.    goto done;  
  18.   } else {//如果是阻塞流處理,則是當前讀取資料進程進入等候狀態,當輸出佇列有緩衝區時喚醒該進程。  
  19.    dprintk(2, "next_buffer: waiting on buffer\n");  
  20.   
  21.    /* Drop lock to avoid deadlock with qbuf */  
  22.    mutex_unlock(&q->vb_lock);  
  23.   
  24. /* Checking list_empty and streaming is safe without locks because we goto checks to validate while  holding locks before proceeding */  
  25. retval=  
  26. wait_event_interruptible(q->wait,!list_empty(&q->stream)|| !q->streaming);  
  27.    mutex_lock(&q->vb_lock);  
  28.   
  29.    if (retval)  
  30.     goto done;  
  31.   
  32.    goto checks;  
  33.   }  
  34.  }  
  35.  retval = 0;  
  36. done:  
  37.  return retval;  
  38. }  



該函數用來判斷視訊緩衝區的狀態是否在佇列和啟動,否則等待
Evideobuf_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. {  
  4.  MAGIC_CHECK(vb->magic, MAGIC_BUFFER);  
  5.   
  6.  if (non_blocking) {//如果是非阻塞流操作操作  
  7.   if (WAITON_CONDITION)//並且等待條件滿足  
  8.    return 0;//則正常返回  
  9.   else  
  10.    return -EAGAIN;//否則返回錯誤碼  
  11.  }  
  12. //如果是阻塞流操作,那麼就會使該進程進入等待佇列  
  13.  if (intr)  
  14.   return wait_event_interruptible(vb->done, WAITON_CONDITION);  
  15.  else  
  16.   wait_event(vb->done, WAITON_CONDITION);  
  17.   
  18.  return 0;  
  19. }  



四、V4L2 層緩衝區參數設置:
1buffer_setup

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


2buffer_prepare

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


3buffer_queue

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


 

  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. 應用程式的呼叫過程:  
  11. 1 reqbufs() -> buf_setup()  
  12.   
  13. 2 querybuf()->videobuf_status()  
  14.   
  15. 3 qbuf()->buf_prepare()  
  16.   
  17. 4 streamon()->buf_queue()  
  18. wake_up_interruptible_sysc(&q->wait)  
  19.   
  20. 5 dqbuf()->stream_next_buffer()->stream_next_buffer_check_queue()  
  21.   
  22. 6 qbuf()->buf_prepare()->buf_queue()  
  23.   

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

文章標籤

創作者介紹
創作者 立你斯 的頭像
立你斯

立你斯學習記錄

立你斯 發表在 痞客邦 留言(0) 人氣()