1.描述符布局
如圖為 bulk 傳輸描述符布局,相對于同步傳輸,批量傳輸只有一個可選擇的配置,沒有備用配置。
VideoControl :無變化
VideoStream:只有一個 bAlternateSetting(刪除alt=1描述符)。同時支持bulk in 端點。
需要修改的地方:
staticstructusb_interface_descriptoruvc_streaming_intf_alt0={ .bLength=USB_DT_INTERFACE_SIZE, .bDescriptorType=USB_DT_INTERFACE, .bInterfaceNumber=UVC_INTF_VIDEO_STREAMING, .bAlternateSetting=0, .bNumEndpoints=1,/*alt0掛一個bulk端點*/ .bInterfaceClass=USB_CLASS_VIDEO, .bInterfaceSubClass=UVC_SC_VIDEOSTREAMING, .bInterfaceProtocol=0x00, .iInterface=0, };
端點描述符:
staticstructusb_endpoint_descriptoruvc_hs_streaming_ep={ .bLength=USB_DT_ENDPOINT_SIZE, .bDescriptorType=USB_DT_ENDPOINT, .bEndpointAddress=USB_DIR_IN, .bmAttributes=USB_ENDPOINT_XFER_BULK, .wMaxPacketSize=512, .bInterval=0, };
2. 控制流程
根據USB規范可知,同步傳輸方式是只要帶中帶有同步端點的接口,系統會定時從設備中讀取數據,無論設備中是否有數據。而如要停止數據的傳輸,只需要選中不帶有同步端點的接口即可。
USB同步傳輸這種靈活的數據傳輸方式是依靠視頻流接口的轉換接口即我們常說的備份接口實現的。在默認情況下數據不傳輸時,視頻數據流接口和備份接口ID為0,其它的備份接口是可根據視頻數據傳輸的大小可按需選擇。
我們知道,批量傳輸只有一個可選擇的altsetting ,那么如何知道設備控制設備的開流和關流動作呢?
2.1 stream on
使用視頻流接口的VS_COMMIT_CONTROL 提交給設備,讓其以指定的數據格式進行數據采樣。
2.2 stream off
關流操作,通過抓包可以看到,通過發送一個clear_halt 請求,來中斷流的操作。
2.3 代碼分析
基于 linux 4.14.281 內核版本:分析host 端uvc 開關流流程
drivers/media/usb/uvc/uvc_queue.c
開流操作:uvc_start_streaming
staticintuvc_start_streaming(structvb2_queue*vq,unsignedintcount) { structuvc_video_queue*queue=vb2_get_drv_priv(vq); structuvc_streaming*stream=uvc_queue_to_stream(queue); unsignedlongflags; intret; queue->buf_used=0; ret=uvc_video_enable(stream,1); if(ret==0) return0; spin_lock_irqsave(&queue->irqlock,flags); uvc_queue_return_buffers(queue,UVC_BUF_STATE_QUEUED); spin_unlock_irqrestore(&queue->irqlock,flags); returnret; }
關流操作:uvc_stop_streaming
staticvoiduvc_stop_streaming(structvb2_queue*vq) { structuvc_video_queue*queue=vb2_get_drv_priv(vq); structuvc_streaming*stream=uvc_queue_to_stream(queue); unsignedlongflags; uvc_video_enable(stream,0); spin_lock_irqsave(&queue->irqlock,flags); uvc_queue_return_buffers(queue,UVC_BUF_STATE_ERROR); spin_unlock_irqrestore(&queue->irqlock,flags); }
重點關注:uvc_video_enable
/* *Enableordisablethevideostream. */ intuvc_video_enable(structuvc_streaming*stream,intenable) { intret; if(!enable){ uvc_uninit_video(stream,1); if(stream->intf->num_altsetting>1){ usb_set_interface(stream->dev->udev, stream->intfnum,0); }else{ /*UVCdoesn'tspecifyhowtoinformabulk-baseddevice *whenthevideostreamisstopped.Windowssendsa *CLEAR_FEATURE(HALT)requesttothevideostreaming *bulkendpoint,mimicthesamebehaviour. */ unsignedintepnum=stream->header.bEndpointAddress &USB_ENDPOINT_NUMBER_MASK; unsignedintdir=stream->header.bEndpointAddress &USB_ENDPOINT_DIR_MASK; unsignedintpipe; pipe=usb_sndbulkpipe(stream->dev->udev,epnum)|dir; usb_clear_halt(stream->dev->udev,pipe); } uvc_video_clock_cleanup(stream); return0; } ret=uvc_video_clock_init(stream); if(ret0) ??return?ret; ?/*?Commit?the?streaming?parameters.?*/ ?ret?=?uvc_commit_video(stream,?&stream->ctrl); if(ret0) ??goto?error_commit; ?ret?=?uvc_init_video(stream,?GFP_KERNEL); ?if?(ret?0) ??goto?error_video; ?return?0; error_video: ?usb_set_interface(stream->dev->udev,stream->intfnum,0); error_commit: uvc_video_clock_cleanup(stream); returnret; }
分析代碼可知:
首先判斷是否關流操作;
如果是,判斷接口的可選配置是否大于1,如果大于1,發送usb_set_interface(intfnum,0) 關流,否則發送usb_clear_halt 請求;
如果是開流操作,發送commit 請求
然后初始化 video
/* *Initializeisochronous/bulkURBsandallocatetransferbuffers. */ staticintuvc_init_video(structuvc_streaming*stream,gfp_tgfp_flags) { structusb_interface*intf=stream->intf; structusb_host_endpoint*ep; unsignedinti; intret; stream->sequence=-1; stream->last_fid=-1; stream->bulk.header_size=0; stream->bulk.skip_payload=0; stream->bulk.payload_size=0; uvc_video_stats_start(stream); if(intf->num_altsetting>1){ structusb_host_endpoint*best_ep=NULL; unsignedintbest_psize=UINT_MAX; unsignedintbandwidth; unsignedintuninitialized_var(altsetting); intintfnum=stream->intfnum; /*Isochronousendpoint,selectthealternatesetting.*/ bandwidth=stream->ctrl.dwMaxPayloadTransferSize; if(bandwidth==0){ uvc_trace(UVC_TRACE_VIDEO,"Devicerequestednull" "bandwidth,defaultingtolowest. "); bandwidth=1; }else{ uvc_trace(UVC_TRACE_VIDEO,"Devicerequested%u" "B/framebandwidth. ",bandwidth); } for(i=0;inum_altsetting;++i){ structusb_host_interface*alts; unsignedintpsize; alts=&intf->altsetting[i]; ep=uvc_find_endpoint(alts, stream->header.bEndpointAddress); if(ep==NULL) continue; /*Checkifthebandwidthishighenough.*/ psize=uvc_endpoint_max_bpi(stream->dev->udev,ep); if(psize>=bandwidth&&psize<=?best_psize)?{ ????altsetting?=?alts->desc.bAlternateSetting; best_psize=psize; best_ep=ep; } } if(best_ep==NULL){ uvc_trace(UVC_TRACE_VIDEO,"Nofastenoughaltsetting" "forrequestedbandwidth. "); return-EIO; } uvc_trace(UVC_TRACE_VIDEO,"Selectingalternatesetting%u" "(%uB/framebandwidth). ",altsetting,best_psize); ret=usb_set_interface(stream->dev->udev,intfnum,altsetting); if(ret0) ???return?ret; ??ret?=?uvc_init_video_isoc(stream,?best_ep,?gfp_flags); ?}?else?{ ??/*?Bulk?endpoint,?proceed?to?URB?initialization.?*/ ??ep?=?uvc_find_endpoint(&intf->altsetting[0], stream->header.bEndpointAddress); if(ep==NULL) return-EIO; /*Rejectbrokendescriptors.*/ if(usb_endpoint_maxp(&ep->desc)==0) return-EIO; ret=uvc_init_video_bulk(stream,ep,gfp_flags); } if(ret0) ??return?ret; ?/*?Submit?the?URBs.?*/ ?for?(i?=?0;?i?urb[i],gfp_flags); if(ret0)?{ ???uvc_printk(KERN_ERR,?"Failed?to?submit?URB?%u?" ?????"(%d). ",?i,?ret); ???uvc_uninit_video(stream,?1); ???return?ret; ??} ?} ?/*?The?Logitech?C920?temporarily?forgets?that?it?should?not?be?adjusting ??*?Exposure?Absolute?during?init?so?restore?controls?to?stored?values. ??*/ ?if?(stream->dev->quirks&UVC_QUIRK_RESTORE_CTRLS_ON_INIT) uvc_ctrl_restore_values(stream->dev); return0; }
從這段代碼可以看出,如果altsetting 大于1 走同步傳輸,發送usb_set_interface(intfnum, altsetting) ,選擇合適帶寬配置。然后初始化同步傳輸管道。
否則,初始化 同步傳輸管道,提交傳輸。
3. 其他注意點
對比同步傳輸和批量傳輸我們可以發現,對于uvc 批量傳輸, 由于沒有同步傳輸類似的多個可選配置,所以沒法靈活控制開流關流操作。特別是在linux 平臺下,要切換不同的格式和分辨率的時候沒有同步傳輸方便。
故,筆者覺得同步傳輸適合傳固定數據,或者對usb camera 做中轉使用比較合適。
對于批量傳輸如果能充分發送usb 吞吐量,(USB2.0)一個微幀傳輸13個packet,理論帶寬將近50MB/s, 筆者實際測試能達到47MB/s,對于YUYV圖像能夠極大提高幀率。
-
接口
+關注
關注
33文章
8911瀏覽量
153104 -
數據傳輸
+關注
關注
9文章
1999瀏覽量
65581 -
控制設備
+關注
關注
0文章
142瀏覽量
10937
原文標題:UVC 批量傳輸技術探討
文章出處:【微信號:漫談嵌入式,微信公眾號:漫談嵌入式】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
淺談剩余電流動作繼電器的在低壓配電系統中的應用
轉帖 剩余電流動作保護器(RCD)的分類、作用、以及接線方式!
剩余電流動作繼電器的應用探討
如何控制IoT ONE Nixie時鐘背光-開/關和顏色

評論