程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> uvc攝像頭代碼解析7

uvc攝像頭代碼解析7

編輯:C++入門知識

13.uvc視頻初始化 13.1 uvc數據流控制 [cpp  struct uvc_streaming_control {       __u16 bmHint;       __u8  bFormatIndex; //視頻格式索引       __u8  bFrameIndex;  //視頻幀索引       __u32 dwFrameInterval;  //視頻幀間隔       __u16 wKeyFrameRate;    //       __u16 wPFrameRate;       __u16 wCompQuality;       __u16 wCompWindowSize;       __u16 wDelay;   //延時       __u32 dwMaxVideoFrameSize;  //最大視頻幀大小       __u32 dwMaxPayloadTransferSize;       __u32 dwClockFrequency; //時鐘頻率       __u8  bmFramingInfo;       __u8  bPreferedVersion;       __u8  bMinVersion;  //版本       __u8  bMaxVersion;  //版本   } __attribute__((__packed__));   13.2 uvc_video_init [cpp]   int uvc_video_init(struct uvc_streaming *stream)   {       struct uvc_streaming_control *probe = &stream->ctrl; //獲取uvc數據流的uvs數據流控制對象       struct uvc_format *format = NULL;       struct uvc_frame *frame = NULL;       unsigned int i;       int ret;       if (stream->nformats == 0) {           uvc_printk(KERN_INFO, "No supported video formats found.\n");           return -EINVAL;       }       atomic_set(&stream->active, 0);       uvc_queue_init(&stream->queue, stream->type, !uvc_no_drop_param); //初始化視頻緩沖區隊列       usb_set_interface(stream->dev->udev, stream->intfnum, 0);  //選擇Alt.Setting 0       if (uvc_get_video_ctrl(stream, probe, 1, UVC_GET_DEF) == 0) //VS_PROBE_CONTROL(GET_DEF)           uvc_set_video_ctrl(stream, probe, 1);                   //VS_PROBE_CONTROL(SET_DEF)       ret = uvc_get_video_ctrl(stream, probe, 1, UVC_GET_CUR);    //VS_PROBE_CONTROL(GET_CUR)       if (ret < 0)           return ret;       for (i = stream->nformats; i > 0; --i) {  //獲取對應的uvc格式           format = &stream->format[i-1];              if (format->index == probe->bFormatIndex) //匹配uvc格式索引值               break;       }       if (format->nframes == 0) {           uvc_printk(KERN_INFO, "No frame descriptor found for the default format.\n");           return -EINVAL;       }       for (i = format->nframes; i > 0; --i) {           frame = &format->frame[i-1]; //獲取對應的uvc幀           if (frame->bFrameIndex == probe->bFrameIndex) //匹配uvc幀索引值               break;       }       probe->bFormatIndex = format->index;      //設置uvc視頻流控制的格式索引為uvc格式的索引       probe->bFrameIndex = frame->bFrameIndex;  //設置uvc視頻流控制的幀索引為uvc幀的索引       stream->cur_format = format;             //設置uvc格式為uvc數據流的cur_format成員       stream->cur_frame = frame;                   //設置uvc幀未uvc數據流的cur_frame成員       /* Select the video decoding function 選擇視頻解碼函數*/       if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {   //視頻采集           if (stream->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)               stream->decode = uvc_video_decode_isight;           else if (stream->intf->num_altsetting > 1)               stream->decode = uvc_video_decode_isoc;  //同步方式           else               stream->decode = uvc_video_decode_bulk;  //bluk方式       }        else {  //視頻播放           if (stream->intf->num_altsetting == 1)               stream->decode = uvc_video_encode_bulk;           else {               uvc_printk(KERN_INFO, "Isochronous endpoints are not supported for video output devices.\n");               return -EINVAL;           }       }       return 0;   }   13.2.1 初始化uvc隊列 [cpp]   void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,int drop_corrupted)   {       mutex_init(&queue->mutex);       spin_lock_init(&queue->irqlock);       INIT_LIST_HEAD(&queue->mainqueue);   //初始化uvc視頻隊列mainqueue鏈表       INIT_LIST_HEAD(&queue->irqqueue);    //初始化uvc視頻隊列irqqueue鏈表       queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0;       queue->type = type;   }     14.uvc V4L2設備 14.1 V4L2操作函數集 [cpp]  const struct v4l2_file_operations uvc_fops = {       .owner      = THIS_MODULE,       .open       = uvc_v4l2_open,    //打開方法       .release             = uvc_v4l2_release,    //釋放方法       .unlocked_ioctl = uvc_v4l2_ioctl,   //控制方法       .read       = uvc_v4l2_read,    //讀方法       .mmap       = uvc_v4l2_mmap,    //映射方法       .poll       = uvc_v4l2_poll,    //輪詢方法   };   14.2 打開方法 14.2.1 相關結構體 [cpp]   struct uvc_fh {//uvc句柄       struct uvc_video_chain *chain;  //uvc視頻鏈       struct uvc_streaming *stream;   //uvc視頻流       enum uvc_handle_state state;   };   14.2.2 open [cpp]   static int uvc_v4l2_open(struct file *file)   {       struct uvc_streaming *stream;       struct uvc_fh *handle;       int ret = 0;          uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n");       stream = video_drvdata(file);   //獲取uvc視頻流       if (stream->dev->state & UVC_DEV_DISCONNECTED)    //設備沒連接           return -ENODEV;       ret = usb_autopm_get_interface(stream->dev->intf);    //喚醒設備       if (ret < 0)           return ret;       /* Create the device handle. */       handle = kzalloc(sizeof *handle, GFP_KERNEL);   //創建uvc句柄       if (handle == NULL) {           usb_autopm_put_interface(stream->dev->intf);           return -ENOMEM;       }       if (atomic_inc_return(&stream->dev->users) == 1) {           ret = uvc_status_start(stream->dev); //uvc狀態開始           if (ret < 0) {               usb_autopm_put_interface(stream->dev->intf);               atomic_dec(&stream->dev->users);               kfree(handle);               return ret;           }       }       handle->chain = stream->chain;    //捆綁uvc句柄和uvc視頻鏈       handle->stream = stream; //捆綁uvc句柄和uvc視頻流       handle->state = UVC_HANDLE_PASSIVE;  //設置uvc狀態為未激活       file->private_data = handle; //將uvc句柄作為文件的私有數據       return 0;   }   14.2.2.1 uvc_status_start啟動狀態 [cpp]   int uvc_status_start(struct uvc_device *dev)   {       if (dev->int_urb == NULL)           return 0;       return usb_submit_urb(dev->int_urb, GFP_KERNEL); //提交urb   }   參看 12.uvc狀態初始化 14.3 控制方法 14.3.1 V4L2的控制方式可以參考下面的資料 linux媒體接口API   常用的命令 [cpp]   VIDIOC_REQBUFS:分配內存    VIDIOC_QUERYBUF:把VIDIOC_REQBUFS中分配的數據緩存轉換成物理地址    VIDIOC_QUERYCAP:查詢驅動功能    VIDIOC_ENUM_FMT:獲取當前驅動支持的視頻格式    VIDIOC_S_FMT:設置當前驅動的頻捕獲格式    VIDIOC_G_FMT:讀取當前驅動的頻捕獲格式    VIDIOC_TRY_FMT:驗證當前驅動的顯示格式    VIDIOC_CROPCAP:查詢驅動的修剪能力    VIDIOC_S_CROP:設置視頻信號的邊框    VIDIOC_G_CROP:讀取視頻信號的邊框    VIDIOC_QBUF:把數據從緩存中讀取出來    VIDIOC_DQBUF:把數據放回緩存隊列    VIDIOC_STREAMON:開始視頻顯示函數    VIDIOC_STREAMOFF:結束視頻顯示函數    VIDIOC_QUERYSTD:檢查當前視頻設備支持的標准,例如PAL或NTSC。    14.3.2 uvc設備V4L2控制方法uvc_v4l2_do_ioctl [cpp]   static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)   {       struct video_device *vdev = video_devdata(file);//獲取V4L2設備       struct uvc_fh *handle = file->private_data;//獲取uvc句柄       struct uvc_video_chain *chain = handle->chain;//獲取uvc視頻鏈       struct uvc_streaming *stream = handle->stream;//獲取uvc視頻流       long ret = 0;          switch (cmd) {       ...       case ...:       {           ...           break;       }       return ret;   }   a.VIDIOC_STREAMON 開始視頻顯示函數 [cpp]   <pre class="cpp" name="code">   case VIDIOC_STREAMON:       {           int *type = arg;           if (*type != stream->type)               return -EINVAL;           if (!uvc_has_privileges(handle))               return -EBUSY;           mutex_lock(&stream->mutex);           ret = uvc_video_enable(stream, 1);  //uvc視頻流使能           mutex_unlock(&stream->mutex);           if (ret < 0)               return ret;           break;       }</pre>a.1 uvc視頻流使能<br>   <pre class="cpp" name="code">int uvc_video_enable(struct uvc_streaming *stream, int enable)   {       int ret;       if (!enable) {           uvc_uninit_video(stream, 1);//逆初始化視頻           usb_set_interface(stream->dev->udev, stream->intfnum, 0);           uvc_queue_enable(&stream->queue, 0);//uvc禁用隊列           return 0;       }       ret = uvc_queue_enable(&stream->queue, 1);   //uvc使能隊列       if (ret < 0)           return ret;       /* Commit the streaming parameters. */       ret = uvc_commit_video(stream, &stream->ctrl);   //uvc提交視頻參數       if (ret < 0)           return ret;       return uvc_init_video(stream, GFP_KERNEL);  //uvc初始化視頻   }</pre>a.1.1 uvc使能隊列   <pre></pre>   <pre class="cpp" name="code"><pre class="cpp" name="code">static int uvc_queue_enable(struct uvc_video_queue *queue, int enable)   {       unsigned int i;       int ret = 0;       mutex_lock(&queue->mutex);       if (enable) {   //使能uvc隊列           if (uvc_queue_streaming(queue)) {   //判斷隊列標志是否為UVC_QUEUE_STREAMING               ret = -EBUSY;               goto done;           }           queue->sequence = 0;           queue->flags |= UVC_QUEUE_STREAMING; //設置隊列標志           queue->buf_used = 0; //設置緩沖區使用標志       }        else {           uvc_queue_cancel(queue, 0); //取消uvc隊列           INIT_LIST_HEAD(&queue->mainqueue);   //重新初始化uvc隊列mainqueue隊列頭           for (i = 0; i < queue->count; ++i)               queue->buffer[i].state = UVC_BUF_STATE_IDLE; //設置緩沖區狀態為閒置態           queue->flags &= ~UVC_QUEUE_STREAMING;    //設置隊列標志       }   done:       mutex_unlock(&queue->mutex);       return ret;   }</pre>a.1.2 uvc提交視頻參數   <pre></pre>   <pre class="cpp" name="code"><pre class="cpp" name="code">int uvc_commit_video(struct uvc_streaming *stream,struct uvc_streaming_control *probe)   {       return uvc_set_video_ctrl(stream, probe, 0);    //uvc設置視頻控制   }</pre><span style="font-family:Arial,Helvetica,sans-serif">a.1.3 uvc初始化視頻</span>   <pre></pre>   <pre class="cpp" name="code"><pre class="cpp" name="code">static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)   {       struct usb_interface *intf = stream->intf;       struct usb_host_endpoint *ep;       unsigned int i;       int ret;       stream->sequence = -1;       stream->last_fid = -1;       stream->bulk.header_size = 0;       stream->bulk.skip_payload = 0;       stream->bulk.payload_size = 0;       if (intf->num_altsetting > 1) {   //同步方式           struct usb_host_endpoint *best_ep = NULL;           unsigned int best_psize = 3 * 1024;           unsigned int bandwidth;           unsigned int uninitialized_var(altsetting);           int intfnum = stream->intfnum;           /* Isochronous endpoint, select the alternate setting. */           bandwidth = stream->ctrl.dwMaxPayloadTransferSize;           if (bandwidth == 0) {               uvc_trace(UVC_TRACE_VIDEO, "Device requested null bandwidth, defaulting to lowest.\n");               bandwidth = 1;           }            else {               uvc_trace(UVC_TRACE_VIDEO, "Device requested %u B/frame bandwidth.\n", bandwidth);           }           for (i = 0; i < intf->num_altsetting; ++i) {               struct usb_host_interface *alts;               unsigned int psize;               alts = &intf->altsetting[i];               ep = uvc_find_endpoint(alts,stream->header.bEndpointAddress);               if (ep == NULL)                   continue;               /* Check if the bandwidth is high enough. */               psize = le16_to_cpu(ep->desc.wMaxPacketSize);               psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));               if (psize >= bandwidth && psize <= best_psize) {                   altsetting = i;                   best_psize = psize;                   best_ep = ep;               }           }           if (best_ep == NULL) {               uvc_trace(UVC_TRACE_VIDEO, "No fast enough alt setting for requested bandwidth.\n");               return -EIO;           }           uvc_trace(UVC_TRACE_VIDEO, "Selecting alternate setting %u (%u B/frame bandwidth).\n", altsetting, best_psize);           ret = usb_set_interface(stream->dev->udev, intfnum, altsetting);           if (ret < 0)               return ret;           ret = uvc_init_video_isoc(stream, best_ep, gfp_flags);  //uvc初始化視頻(同步方法)       }        else {  //Bulk方式           /* Bulk endpoint, proceed to URB initialization. */           ep = uvc_find_endpoint(&intf->altsetting[0],stream->header.bEndpointAddress);           if (ep == NULL)               return -EIO;           ret = uvc_init_video_bulk(stream, ep, gfp_flags);   //uvc初始化視頻(bulk方法)       }       if (ret < 0)           return ret;       /* Submit the URBs. */       for (i = 0; i < UVC_URBS; ++i) {           ret = usb_submit_urb(stream->urb[i], gfp_flags); //提交urb           if (ret < 0) {               uvc_printk(KERN_ERR, "Failed to submit URB %u (%d).\n", i, ret);               uvc_uninit_video(stream, 1);               return ret;           }       }          return 0;   }</pre>a.1.3.1 同步方式   <pre></pre>   <pre class="cpp" name="code"><pre class="cpp" name="code">static int uvc_init_video_isoc(struct uvc_streaming *stream,struct usb_host_endpoint *ep, gfp_t gfp_flags)   {       struct urb *urb;       unsigned int npackets, i, j;       u16 psize;       u32 size;       psize = le16_to_cpu(ep->desc.wMaxPacketSize);       psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));       size = stream->ctrl.dwMaxVideoFrameSize;       npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags);   //分配urb緩沖區       if (npackets == 0)           return -ENOMEM;       size = npackets * psize;       for (i = 0; i < UVC_URBS; ++i) {           urb = usb_alloc_urb(npackets, gfp_flags);   //分配urb           if (urb == NULL) {               uvc_uninit_video(stream, 1);               return -ENOMEM;           }           urb->dev = stream->dev->udev;  //設置urb           urb->context = stream;           urb->pipe = usb_rcvisocpipe(stream->dev->udev,ep->desc.bEndpointAddress);           urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;           urb->interval = ep->desc.bInterval;           urb->transfer_buffer = stream->urb_buffer[i];           urb->transfer_dma = stream->urb_dma[i];           urb->complete = uvc_video_complete;           urb->number_of_packets = npackets;           urb->transfer_buffer_length = size;           for (j = 0; j < npackets; ++j) {               urb->iso_frame_desc[j].offset = j * psize;               urb->iso_frame_desc[j].length = psize;           }           stream->urb[i] = urb;       }       return 0;   }</pre><span style="font-family:Arial,Helvetica,sans-serif">a.1.3.2 Bluk方式</span>   <pre></pre>   <pre class="cpp" name="code"><pre class="cpp" name="code">static int uvc_init_video_bulk(struct uvc_streaming *stream,struct usb_host_endpoint *ep, gfp_t gfp_flags)   {       struct urb *urb;       unsigned int npackets, pipe, i;       u16 psize;       u32 size;       psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff;       size = stream->ctrl.dwMaxPayloadTransferSize;       stream->bulk.max_payload_size = size;       npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags);   //分配urb緩沖區       if (npackets == 0)           return -ENOMEM;       size = npackets * psize;       if (usb_endpoint_dir_in(&ep->desc))           pipe = usb_rcvbulkpipe(stream->dev->udev,ep->desc.bEndpointAddress);       else           pipe = usb_sndbulkpipe(stream->dev->udev,ep->desc.bEndpointAddress);          if (stream->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)           size = 0;       for (i = 0; i < UVC_URBS; ++i) {           urb = usb_alloc_urb(0, gfp_flags);  //分配urb           if (urb == NULL) {               uvc_uninit_video(stream, 1);               return -ENOMEM;           }           usb_fill_bulk_urb(urb, stream->dev->udev, pipe,stream->urb_buffer[i], size, uvc_video_complete,stream);    //設置urb           urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;           urb->transfer_dma = stream->urb_dma[i];           stream->urb[i] = urb;       }       return 0;   }</pre><pre class="cpp" name="code"><span style="font-family:Arial, Helvetica, sans-serif;"></span><pre class="cpp" name="code">a.1.3.1 同步方式和<span style="font-family:Arial, Helvetica, sans-serif;">a.1.3.2 Bluk方式 兩種方式初始化uvc視頻主要是分配設置urb,然後在</span><span style="font-family:Arial, Helvetica, sans-serif;">uvc_init_video函數中又通過</span><span style="font-family:Arial, Helvetica, sans-serif;">usb_submit_urb提交了urb,</span></pre><pre class="cpp" name="code"><span style="font-family:Arial, Helvetica, sans-serif;">兩種方法的urb回調函數都是uvc_video_complete</span></pre><pre class="cpp" name="code"><span style="font-family:Arial, Helvetica, sans-serif;">a.2 urb回調函數uvc_video_complete</span></pre><pre class="cpp" name="code"><span style="font-family:Arial, Helvetica, sans-serif;"></span><pre class="cpp" name="code">static void uvc_video_complete(struct urb *urb)   {       struct uvc_streaming *stream = urb->context;       struct uvc_video_queue *queue = &stream->queue;       struct uvc_buffer *buf = NULL;       unsigned long flags;       int ret;       switch (urb->status) {       case 0:           break;       default:           uvc_printk(KERN_WARNING, "Non-zero status (%d) in video completion handler.\n", urb->status);       case -ENOENT:       /* usb_kill_urb() called. */           if (stream->frozen)               return;       case -ECONNRESET:   /* usb_unlink_urb() called. */       case -ESHUTDOWN:    /* The endpoint is being disabled. */           uvc_queue_cancel(queue, urb->status == -ESHUTDOWN);           return;       }       spin_lock_irqsave(&queue->irqlock, flags);       if (!list_empty(&queue->irqqueue))           buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,queue);       spin_unlock_irqrestore(&queue->irqlock, flags);       stream->decode(urb, stream, buf);    //調用uvc視頻流的decode方法       if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {   //再次提交urb           uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",ret);       }   }</pre>對於同步和bilk方式的decode方法分別是   <pre></pre>   <pre class="cpp" name="code"><span style="font-family:Arial, Helvetica, sans-serif;"><span style="WHITE-SPACE: pre">    </span>stream->decode = uvc_video_decode_isoc   <span style="WHITE-SPACE: pre"> </span>stream->decode = uvc_video_encode_bulk;   這個在前面uvc_video_init函數中設置了</span></pre>   <pre></pre>   ok後面就開始解碼了   <pre></pre>   <pre></pre>   <pre></pre>   <pre></pre>   <pre></pre>   <pre></pre>   <pre></pre>   <pre></pre>   <pre></pre>   <pre></pre>   <pre></pre>   <pre></pre>   <pre></pre>   <pre></pre>   <pre></pre>   <pre></pre>   <pre></pre>   <pre></pre>   <pre></pre>   <pre></pre>   </pre></pre></pre></pre></pre></pre></pre>          

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved