c语言sscanf函数的用法是什么
304
2022-11-17
如何知道设备控制设备的开流和关流动作
1.描述符布局
如图为 bulk 传输描述符布局,相对于同步传输,批量传输只有一个可选择的配置,没有备用配置。
VideoControl :无变化
需要修改的地方:
端点描述符:
2. 控制流程
根据USB规范可知,同步传输方式是只要带中带有同步端点的接口,系统会定时从设备中读取数据,无论设备中是否有数据。而如要停止数据的传输,只需要选中不带有同步端点的接口即可。
我们知道,批量传输只有一个可选择的altsetting ,那么如何知道设备控制设备的开流和关流动作呢?
2.1 stream on
使用视频流接口的VS_COMMIT_CONTROL 提交给设备,让其以指定的数据格式进行数据采样。
2.2 stream off
关流操作,通过抓包可以看到,通过发送一个clear_halt 请求,来中断流的操作。
2.3 代码分析
drivers/media/usb/uvc/uvc_queue.c
开流操作:uvc_start_streaming
关流操作: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(ret< 0) return ret; /* Commit the streaming parameters. */ ret = uvc_commit_video(stream, &stream->ctrl);if(ret< 0) 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;i< intf->num_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(ret< 0) 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(ret< 0) return ret; /* Submit the URBs. */ for (i = 0; i < UVC_URBS; ++i) { ret = usb_submit_urb(stream->urb[i],gfp_flags);if(ret< 0) { 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图像能够极大提高帧率。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~