Chinaunix首页 | 论坛 | 博客
  • 博客访问: 539856
  • 博文数量: 252
  • 博客积分: 1068
  • 博客等级: 少尉
  • 技术积分: 1775
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-05 21:33
文章分类

全部博文(252)

文章存档

2013年(21)

2012年(231)

分类: 嵌入式

2013-11-25 15:16:23

来源:http://blog.csdn.net/myarrow/article/details/8475728

1. VIDIOC_REQBUFS: 请求Kernel分配Video Buffer

其申请流程如下图所示:

1.1  Kernel态相关数据结构

  1. struct uvc_fh {  
  2.     struct uvc_video_chain *chain;  
  3.     struct uvc_streaming *stream;  //Stream--->  
  4.     enum uvc_handle_state state;  
  5. };  
  6.   
  7. struct uvc_streaming {  
  8.     struct list_head list;  
  9.     struct uvc_device *dev;  
  10.     struct video_device *vdev;  
  11.     struct uvc_video_chain *chain;  
  12.     atomic_t active;  
  13.   
  14.     struct usb_interface *intf;  
  15.     int intfnum;  
  16.     __u16 maxpsize;  
  17.   
  18.     struct uvc_streaming_header header;  
  19.     enum v4l2_buf_type type;  
  20.   
  21.     unsigned int nformats;  
  22.     struct uvc_format *format;  
  23.   
  24.     struct uvc_streaming_control ctrl;  
  25.     struct uvc_format *cur_format;  
  26.     struct uvc_frame *cur_frame;  
  27.     /* Protect access to ctrl, cur_format, cur_frame and hardware video 
  28.      * probe control. 
  29.      */  
  30.     struct mutex mutex;  
  31.   
  32.     unsigned int frozen : 1;  
  33.     struct uvc_video_queue queue; // UVC Video Queue--->  
  34.     void (*decode) (struct urb *urb, struct uvc_streaming *video,  
  35.             struct uvc_buffer *buf);  
  36.   
  37.     /* Context data used by the bulk completion handler. */  
  38.     struct {  
  39.         __u8 header[256];  
  40.         unsigned int header_size;  
  41.         int skip_payload;  
  42.         __u32 payload_size;  
  43.         __u32 max_payload_size;  
  44.     } bulk;  
  45.   
  46.     struct urb *urb[UVC_URBS];  
  47.     char *urb_buffer[UVC_URBS];  
  48.     dma_addr_t urb_dma[UVC_URBS];  
  49.     unsigned int urb_size;  
  50.   
  51.     __u32 sequence;  
  52.     __u8 last_fid;  
  53.   
  54.     struct tasklet_struct *tasklet[UVC_URBS];     /* ddl@rock-chips.com */  
  55. };  
  56.   
  57. struct uvc_video_queue {  
  58.     enum v4l2_buf_type type;  
  59.   
  60.     void *mem;             // 已经分配的连续虚拟内存的首地址  
  61.     unsigned int flags;  
  62.   
  63.     unsigned int count;    // 已分配的buffer个数  
  64.     unsigned int buf_size; // 每个buffer的大小  
  65.     unsigned int buf_used;  
  66.     struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS];  // UVC buffer--->  
  67.     struct mutex mutex; /* protects buffers and mainqueue */  
  68.     spinlock_t irqlock; /* protects irqqueue */  
  69.   
  70.     wait_queue_head_t wait; /* wait if mainqueue is empty */  
  71.   
  72.     struct list_head mainqueue;  
  73.     struct list_head irqqueue;  
  74.       
  75. };  
  76.   
  77. struct uvc_buffer {  
  78.     unsigned long vma_use_count;  
  79.     struct list_head stream;  
  80.   
  81.     /* Touched by interrupt handler. */  
  82.     struct v4l2_buffer buf;     // v4l2_buffer --->  
  83.     struct list_head queue;  
  84.     wait_queue_head_t wait;     // 初始化等待队列  
  85.     enum uvc_buffer_state state;  
  86.     unsigned int error;  
  87. };  
  88.   
  89. struct v4l2_buffer {  
  90.     __u32           index;    //buffer索引  
  91.     enum v4l2_buf_type      type;     //如V4L2_BUF_TYPE_VIDEO_CAPTURE  
  92.     __u32           bytesused;  
  93.     __u32           flags;  
  94.     enum v4l2_field     field;    // V4L2_FIELD_NONE  
  95.     struct timeval      timestamp;   
  96.     struct v4l2_timecode    timecode;  
  97.     __u32           sequence;  
  98.   
  99.     /* memory location */  
  100.     enum v4l2_memory        memory;   // V4L2_MEMORY_MMAP  
  101.     union {  
  102.         __u32           offset;   //在已经分配的大块内存中的偏移量,  
  103.                                           //其首地址保存在uvc_video_queue->mem中  
  104.         unsigned long   userptr;  
  105.         struct v4l2_plane *planes;  
  106.     } m;  
  107.     __u32           length;   //申请的内存大小  
  108.     __u32           input;  
  109.     __u32           reserved;  
  110. };  


1.2 uvc_alloc_buffers实现代码

  1. /* 
  2.  * Allocate the video buffers. 
  3.  * 
  4.  * Pages are reserved to make sure they will not be swapped, as they will be 
  5.  * filled in the URB completion handler. 
  6.  * 
  7.  * Buffers will be individually mapped, so they must all be page aligned. 
  8.  */  
  9. int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,  
  10.         unsigned int buflength)  
  11. {  
  12.     unsigned int bufsize = PAGE_ALIGN(buflength);  
  13.     unsigned int i;  
  14.     void *mem = NULL;  
  15.     int ret;  
  16.   
  17.     if (nbuffers > UVC_MAX_VIDEO_BUFFERS)  
  18.         nbuffers = UVC_MAX_VIDEO_BUFFERS;  
  19.   
  20.     mutex_lock(&queue->mutex);  
  21.   
  22.     if ((ret = __uvc_free_buffers(queue)) < 0)  
  23.         goto done;  
  24.   
  25.     /* Bail out if no buffers should be allocated. */  
  26.     if (nbuffers == 0)  
  27.         goto done;  
  28.   
  29.     /* Decrement the number of buffers until allocation succeeds. */  
  30.     for (; nbuffers > 0; --nbuffers) {  
  31.         mem = vmalloc_32(nbuffers * bufsize);  
  32.         if (mem != NULL)  
  33.             break;  
  34.     }  
  35.   
  36.     if (mem == NULL) {  
  37.         ret = -ENOMEM;  
  38.         goto done;  
  39.     }  
  40.   
  41.     for (i = 0; i < nbuffers; ++i) {  
  42.         memset(&queue->buffer[i], 0, sizeof queue->buffer[i]);  
  43.         queue->buffer[i].buf.index = i;  
  44.         queue->buffer[i].buf.m.offset = i * bufsize;  
  45.         queue->buffer[i].buf.length = buflength;  
  46.         queue->buffer[i].buf.type = queue->type;  
  47.         queue->buffer[i].buf.field = V4L2_FIELD_NONE;  
  48.         queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP;  
  49.         queue->buffer[i].buf.flags = 0;  
  50.         init_waitqueue_head(&queue->buffer[i].wait);  
  51.     }  
  52.   
  53.     queue->mem = mem;  
  54.     queue->count = nbuffers;  
  55.     queue->buf_size = bufsize;  
  56.     ret = nbuffers;  
  57.   
  58. done:  
  59.     mutex_unlock(&queue->mutex);  
  60.     return ret;  
  61. }  


 2. VIDIOC_QUERYBUF: 把Kernel分配的内存映射到用户空间

 

 

 3. VIDIOC_QBUF: 把uvc_buffer放入队列中

 

 

  1. /* 
  2.  * Queue a video buffer. Attempting to queue a buffer that has already been 
  3.  * queued will return -EINVAL. 
  4.  */  
  5. int uvc_queue_buffer(struct uvc_video_queue *queue,  
  6.     struct v4l2_buffer *v4l2_buf)  
  7. {  
  8.     struct uvc_buffer *buf;  
  9.     unsigned long flags;  
  10.     int ret = 0;  
  11.   
  12.     uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index);  
  13.   
  14.     if (v4l2_buf->type != queue->type ||  
  15.         v4l2_buf->memory != V4L2_MEMORY_MMAP) {  
  16.         uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) "  
  17.             "and/or memory (%u).\n", v4l2_buf->type,  
  18.             v4l2_buf->memory);  
  19.         return -EINVAL;  
  20.     }  
  21.   
  22.     mutex_lock(&queue->mutex);  
  23.     if (v4l2_buf->index >= queue->count) {  
  24.         uvc_trace(UVC_TRACE_CAPTURE, "[E] Out of range index.\n");  
  25.         ret = -EINVAL;  
  26.         goto done;  
  27.     }  
  28.   
  29.     buf = &queue->buffer[v4l2_buf->index];  
  30.     if (buf->state != UVC_BUF_STATE_IDLE) {  
  31.         uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer state "  
  32.             "(%u).\n", buf->state);  
  33.         ret = -EINVAL;  
  34.         goto done;  
  35.     }  
  36.   
  37.     if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&  
  38.         v4l2_buf->bytesused > buf->buf.length) {  
  39.         uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");  
  40.         ret = -EINVAL;  
  41.         goto done;  
  42.     }  
  43.   
  44.     spin_lock_irqsave(&queue->irqlock, flags);  
  45.     if (queue->flags & UVC_QUEUE_DISCONNECTED) {  
  46.         spin_unlock_irqrestore(&queue->irqlock, flags);  
  47.         ret = -ENODEV;  
  48.         goto done;  
  49.     }  
  50.     buf->state = UVC_BUF_STATE_QUEUED;  
  51.     if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)  
  52.         buf->buf.bytesused = 0;  
  53.     else  
  54.         buf->buf.bytesused = v4l2_buf->bytesused;  
  55.   
  56.     list_add_tail(&buf->stream, &queue->mainqueue);  
  57.     list_add_tail(&buf->queue, &queue->irqqueue);  
  58.     spin_unlock_irqrestore(&queue->irqlock, flags);  
  59.   
  60. done:  
  61.     mutex_unlock(&queue->mutex);  
  62.     return ret;  
  63. }  


 4. VIDIOC_STREAMON: 做好准备工作并提交URB请求

 

  1. /* 
  2.  * Initialize bulk URBs and allocate transfer buffers. The packet size is 
  3.  * given by the endpoint. 
  4.  */  
  5. static int uvc_init_video_bulk(struct uvc_streaming *stream,  
  6.     struct usb_host_endpoint *ep, gfp_t gfp_flags)  
  7. {  
  8.     struct urb *urb;  
  9.     unsigned int npackets, pipe, i;  
  10.     u16 psize;  
  11.     u32 size;  
  12.           
  13.     // 获取每个包的大小  
  14.     psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff;  
  15.       
  16.     // 一次可传输的最大负荷传输大小  
  17.     size = stream->ctrl.dwMaxPayloadTransferSize;  
  18.     stream->bulk.max_payload_size = size;  
  19.       
  20.     /* 
  21.     分配置urb传输buffer,返回包个数(size/psize),它指每个urb 
  22.     包含多少个包; 为每个stream->urb_buffer分配DMA buffer,如下: 
  23.     for (i = 0; i < UVC_URBS; ++i) { 
  24.         stream->urb_size = psize * npackets; // urb_buffer的大小 
  25.  
  26.         //分配DMA内存,并把地址保存在urb_buffer[i]和urb_dma[i]中, 
  27.         //同一块内存,不同的表示方法 
  28.         //1) stream->urb_buffer[i] = offset + page->vaddr; 
  29.         //2) stream->urb_dma[i] = offset + page->dma; 
  30.  
  31.         stream->urb_buffer[i] = usb_alloc_coherent( 
  32.                      stream->dev->udev, stream->urb_size, 
  33.                      gfp_flags | __GFP_NOWARN, &stream->urb_dma[i]); 
  34.  
  35.         if (!stream->urb_buffer[i]) { 
  36.             uvc_free_urb_buffers(stream); 
  37.             break; 
  38.         } 
  39.     } 
  40.     */  
  41.     npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags);  
  42.     if (npackets == 0)  
  43.         return -ENOMEM;  
  44.   
  45.     size = npackets * psize;  
  46.   
  47.     if (usb_endpoint_dir_in(&ep->desc))  
  48.         pipe = usb_rcvbulkpipe(stream->dev->udev,  
  49.                        ep->desc.bEndpointAddress);  
  50.     else  
  51.         pipe = usb_sndbulkpipe(stream->dev->udev,  
  52.                        ep->desc.bEndpointAddress);  
  53.   
  54.     if (stream->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)  
  55.         size = 0;  
  56.   
  57.     for (i = 0; i < UVC_URBS; ++i) {  
  58.   
  59.         // 创建一个 urb  
  60.         urb = usb_alloc_urb(0, gfp_flags);  
  61.         if (urb == NULL) {  
  62.             uvc_uninit_video(stream, 1);  
  63.             return -ENOMEM;  
  64.         }  
  65.   
  66.         /* 填充urb参数 
  67.         struct urb { 
  68.             void *transfer_buffer;  // (in) associated data buffer 
  69.             dma_addr_t transfer_dma;// (in) dma addr for transfer_buffer 
  70.             usb_complete_t complete;// (in) completion routine 
  71.             struct usb_iso_packet_descriptor iso_frame_desc[0]; 
  72.                                     // (in) ISO ONLY 
  73.         }        
  74.         */  
  75.         usb_fill_bulk_urb(urb, stream->dev->udev, pipe,  
  76.                           stream->urb_buffer[i],  //传输buffer  
  77.                           size,        //传输buffer的大小  
  78.                           uvc_video_complete, //URB请求完成之后的callback  
  79.                           stream);  
  80.   
  81.         urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;  
  82.         urb->transfer_dma = stream->urb_dma[i]; //给urb->transfer_dma赋值  
  83.         // 把此urb保存到stream->urb[i]中  
  84.         stream->urb[i] = urb;  
  85.     }  
  86.   
  87.     return 0;  
  88. }  


5. urb数据解析 (uvc_video_complete)

       当URB请求(usb_submit_urb)完成之后,它将调用其回调函数(uvc_video_complete),下面分析此回调函数到底做了些什 么。即如何把transfer_buffer或transfer_dma中数据转换为应用程序需要的v4l2_buffer中的数据。

 5.1 uvc_video_complete

  1. static void uvc_video_complete(struct urb *urb)  
  2. {      
  3.     struct uvc_streaming *stream = urb->context;  
  4.     struct uvc_video_queue *queue = &stream->queue;  
  5.     struct uvc_buffer *buf = NULL;  
  6.     unsigned long flags;  
  7.     int ret;  
  8.   
  9.     switch (urb->status) {  
  10.     case 0:  
  11.         break;  
  12.   
  13.     default:  
  14.         uvc_printk(KERN_WARNING, "Non-zero status (%d) in video "  
  15.             "completion handler.\n", urb->status);  
  16.   
  17.     case -ENOENT:       /* usb_kill_urb() called. */  
  18.         if (stream->frozen)  
  19.             return;  
  20.   
  21.     case -ECONNRESET:   /* usb_unlink_urb() called. */  
  22.     case -ESHUTDOWN:    /* The endpoint is being disabled. */  
  23.         uvc_queue_cancel(queue, urb->status == -ESHUTDOWN);  
  24.         return;  
  25.     }  
  26.    
  27.     spin_lock_irqsave(&queue->irqlock, flags);  
  28.     if (!list_empty(&queue->irqqueue))  
  29.         buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,  
  30.                        queue);//从queue->irqqueue中取出一个空的uvc_buffer  
  31.     spin_unlock_irqrestore(&queue->irqlock, flags);  
  32.         //把urb中的数据转换为uvc_buffer中的数据,并设置对应的状态  
  33.     stream->decode(urb, stream, buf);  
  34.   
  35.     if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {  
  36.         uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",  
  37.             ret);  
  38.     }  
  39. }  

5.2  stream->decode是什么?

        现在关键是stream->decode到底做了些什么?它也是一个回调函数,首先要搞明白它是一个什么函数,其注册过程如下图所示:

5.3 uvc_video_decode_bulk

 

 

5.4 uvc_video_decode_isoc

  1. static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,  
  2.     struct uvc_buffer *buf)  
  3. {  
  4.     u8 *mem;  
  5.     int ret, i;  
  6.   
  7.     for (i = 0; i < urb->number_of_packets; ++i) {  
  8.         if (urb->iso_frame_desc[i].status < 0) {  
  9.             uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame "  
  10.                 "lost (%d).\n", urb->iso_frame_desc[i].status);  
  11.             /* Mark the buffer as faulty. */  
  12.             if (buf != NULL)  
  13.                 buf->error = 1;  
  14.             continue;  
  15.         }  
  16.   
  17.         /* Decode the payload header. */  
  18.         mem = urb->transfer_buffer + urb->iso_frame_desc[i].offset;  
  19.         do {  
  20.             ret = uvc_video_decode_start(stream, buf, mem,  
  21.                 urb->iso_frame_desc[i].actual_length);  
  22.             if (ret == -EAGAIN)  
  23.                 buf = uvc_queue_next_buffer(&stream->queue,  
  24.                                 buf);  
  25.         } while (ret == -EAGAIN);  
  26.   
  27.         if (ret < 0)  
  28.             continue;  
  29.   
  30.         /* Decode the payload data. */  
  31.         uvc_video_decode_data(stream, buf, mem + ret,  
  32.             urb->iso_frame_desc[i].actual_length - ret);  
  33.   
  34.         /* Process the header again. */  
  35.         uvc_video_decode_end(stream, buf, mem,  
  36.             urb->iso_frame_desc[i].actual_length);  
  37.   
  38.         if (buf->state == UVC_BUF_STATE_READY) {  
  39.             if (buf->buf.length != buf->buf.bytesused &&  
  40.                 !(stream->cur_format->flags &  
  41.                   UVC_FMT_FLAG_COMPRESSED))  
  42.                 buf->error = 1;  
  43.   
  44.             buf = uvc_queue_next_buffer(&stream->queue, buf);  
  45.         }  
  46.     }  
  47. }  


 

6. VIDIOC_DQBUF: 获取视频数据

 

  7. CameraHAL工作流程

阅读(2881) | 评论(0) | 转发(0) |
0

上一篇:Linux内核编译与安装

下一篇:没有了

给主人留下些什么吧!~~