0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

UVC bulk传输实现思路

漫谈嵌入式 来源: 漫谈嵌入式 2023-09-25 10:00 次阅读

前段时间有个读者咨询UVC bulk 传输实现,接着这个机会重新梳理一遍UVC bulk 传输实现思路,同时对比ISO 与 Bulk 实现不同。有关bulk 传输实现请先看前文

阅读此文前提:假设读者,已知晓UVC 协议,以及UVC 设备驱动框架

1. 描述符布局

1.1 ISO 传输

1525fe18-5ae6-11ee-939d-92fbcf53809c.png

ISO 传输模式下的描述符布局如上图所示:

一个配置

两个接口:Video Control / Video Stream

接口0:VideoControl。处理 UVC CT/PU/XU 等处理,主要用来控制接口1:VideoStream。处理UVC 视频流控制。

一个VideoControl 可以关联一个或者多个流接口。每个流接口下面,关联2个多或者多个接口配置。

对于ISO 传输,流接口下有多个备用接口,用来控制视频流的传输。一般用alt0 关流,altx 开流。

1.2 BULK 传输

153f1eca-5ae6-11ee-939d-92fbcf53809c.png

BULK 传输模式下的描述符布局如上图所示:

一个配置

两个接口:Video Control / Video Stream

接口0:VideoControl。处理 UVC CT/PU/XU 等处理,主要用来控制接口1:VideoStream。处理UVC 视频流控制。

对于BULK 传输, 与ISO 模式最大的不同,是流接口只有一个alt0 接口配置。故,对其视频流的控制流程,相比较ISO 模式比较复杂一些。

2. 控制流程

2.1 ISO 传输

根据USB规范可知,同步传输方式是只要选中中带有同步端点的接口,系统会定时从设备中读取数据,无论设备中是否有数据。而如要停止数据的传输,只需要选中不带有同步端点的接口即可。

USB同步传输这种灵活的数据传输方式是依靠视频流接口的转换接口即我们常说的备份接口实现的。

Stream ON:

155189e8-5ae6-11ee-939d-92fbcf53809c.png

Stream OFF:

1578d534-5ae6-11ee-939d-92fbcf53809c.png

整个视频流的控制流程(开流/关流),可以在设备收到set_alt1/0 后进行处理。

2.2 BULK 传输

从描述符上分析 UVC 的 bulk 传输只有一个备用接口。故无法通过ISO 模式下通过备用接口进行开关流控制。

StreamOn:

15963732-5ae6-11ee-939d-92fbcf53809c.png

StreamOff

15c6f084-5ae6-11ee-939d-92fbcf53809c.png

通过抓包对比发现,开流过程通过uvc probe 与commit 流程处理。关流过程主机会下发一个clear_halt 请求。在clear_halt 请求里面做关流的后处理。

通过对比发现,对于ISO 传输,针对UVC 的设备描述修改基本不大,难处理的是UVC 的控制流程,特别是视频流的处理,接下来我们会以linux 平台介绍如何在iso 基础上修改为 bulk 模式

3. 源码分析

我们以linux 平台举例,其他平台只要熟悉uvc 底层协议,即可快速迁移。

3.1 host 端

源码位置:driver/media/uvc/uvc_queue.c

uvc 使能:

intuvc_video_enable(structuvc_streaming*stream,intenable)
{
intret;

if(!enable){
...
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.
*/

......
usb_clear_halt(stream->dev->udev,pipe);
}
......
return0;
}

/*Committhestreamingparameters.*/
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;
}

StreamOn:

uvc_start_streaming()//
ret=uvc_video_enable(stream,1);

StreamOff:

uvc_stop_streaming();
uvc_video_enable(stream,0);

从host 端源码分析和我们猜想得到了印证:

开流发送commit 请求

关流发送clear_halt 请求

视频传输:源码参考:driver/media/usb/uvc_video.c

//usbcomplete中断
staticvoiduvc_video_complete(structurb*urb)
{
structuvc_streaming*stream=urb->context;
structuvc_video_queue*queue=&stream->queue;
structuvc_buffer*buf=NULL;
unsignedlongflags;
intret;

switch(urb->status){
case0:
break;

default:
uvc_printk(KERN_WARNING,"Non-zerostatus(%d)invideo"
"completionhandler.
",urb->status);
/*fallthrough*/
case-ENOENT:/*usb_kill_urb()called.*/
if(stream->frozen)
return;
/*fallthrough*/
case-ECONNRESET:/*usb_unlink_urb()called.*/
case-ESHUTDOWN:/*Theendpointisbeingdisabled.*/
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,structuvc_buffer,
queue);
spin_unlock_irqrestore(&queue->irqlock,flags);

/*视频解码:视频传输关键*/
stream->decode(urb,stream,buf);

/*提交urb*/
if((ret=usb_submit_urb(urb,GFP_ATOMIC))< 0) {
  uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).
",
   ret);
 }
}

host 端视频数据解码:

stream->decode(urb,stream,buf);
uvc_video_decode_bulk();
uvc_video_decode_start();//解析uvcheader
uvc_video_decode_data();//解析视频数据
uvc_video_decode_end();//帧结束标记

3.2 device 端

源码位置:driver/usb/gadget/function

ISO 开关流

staticintuvc_function_set_alt(structusb_function*f,unsignedinterface,unsignedalt)
{
.......
/*VideoControlprocess*/
if(interface==uvc->control_intf){
/*复位控制端点*/
usb_ep_disable(uvc->control_ep);
...
usb_ep_enable(uvc->control_ep);

if(uvc->state==UVC_STATE_DISCONNECTED){
/*提交uvc状态*/
memset(&v4l2_event,0,sizof(v4l2_evetn);
v4l2_event.type=UVC_EVENT_CONNECT;
uvc_event->speed=cdev->gadget->speed;
v4l2_event_queue(&uvc->vdev,&v4l2_event);
uvc->state=UVC_STATE_CONNECTED;
}

return0;

}
/*VideoStreamprocess*/
if(interface!=uvc->streaming_intf){
return-EINVAL;
}

/*判断端点是否为bulk 端点:*/
if(usb_endpoint_xfer_bulk(&uvc->desc.vs_ep)){
/*使能端点*/
usb_ep_enable(uvc->video_ep);
returnalt?-EIVAL:0;
}

/*ISO开关流处理*/
switch(alt){
case0:
if(uvc->state!=UVC_STATE_STREAMING)
return0;

if(uvc->video.ep)
usb_ep_disable(uvc->video.ep);

/*提交应用:关流*/
memset(&v4l2_event,0,sizeof(v4l2_event));
v4l2_event.type=UVC_EVENT_STREAMOFF;
v4l2_event_queue(&uvc->vdev,&v4l2_event);

uvc->state=UVC_STATE_CONNECTED;
return0;

case1:
if(uvc->state!=UVC_STATE_CONNECTED)
return0;

if(!uvc->video.ep)
return-EINVAL;

INFO(cdev,"resetUVC
");
usb_ep_disable(uvc->video.ep);

ret=config_ep_by_speed(f->config->cdev->gadget,
&(uvc->func),uvc->video.ep);
if(ret)
returnret;
usb_ep_enable(uvc->video.ep);

/*开流*/
memset(&v4l2_event,0,sizeof(v4l2_event));
v4l2_event.type=UVC_EVENT_STREAMON;
v4l2_event_queue(&uvc->vdev,&v4l2_event);
returnUSB_GADGET_DELAYED_STATUS;

default:
return-EINVAL;
}

}

bulk 传输开关流

uvc_function_setup(structusb_function*f,conststructusb_ctrlrequest*ctrl)
{
structuvc_device*uvc=to_uvc(f);
structv4l2_eventv4l2_event;
structuvc_event*uvc_event=(void*)&v4l2_event.u.data;

/*printk(KERN_INFO"setuprequest%02x%02xvalue%04xindex%04x%04x
",
*ctrl->bRequestType,ctrl->bRequest,le16_to_cpu(ctrl->wValue),
*le16_to_cpu(ctrl->wIndex),le16_to_cpu(ctrl->wLength));
*/

if((ctrl->bRequestType&USB_TYPE_MASK)!=USB_TYPE_CLASS){
/* bulk 传输关流:需要修改udc 控制器,将usb 控制器clear_halt 注册到uvc function 驱动里面*/
if(usb_endpoint_xfer_bulk(&uvc->desc.vs_ep)){
memset(&v4l2_event,0,sizeof(v4l2_event));
v4l2_event.type=UVC_EVENT_STREANOFF;
memcpy(&uvc_event->req,ctrl,sizeof(uvc_event->req));
v4l2_event_queue(&uvc->vdev,&v4l2_event);

}else{
INFO(f->config->cdev,"invalidrequesttype
");
return-EINVAL;
}

}

/*Stalltoobigrequests.*/
if(le16_to_cpu(ctrl->wLength)>UVC_MAX_REQUEST_SIZE)
return-EINVAL;

/*Tellthecompletecallbacktogenerateaneventforthenextrequest
*thatwillbeenqueuedbyUVCIOC_SEND_RESPONSE.
*/
uvc->event_setup_out=!(ctrl->bRequestType&USB_DIR_IN);
uvc->event_length=le16_to_cpu(ctrl->wLength);

/* bulk 传输开流:通过uvc probe 和 commit 提交分辨率和帧率控制*/
memset(&v4l2_event,0,sizeof(v4l2_event));
v4l2_event.type=UVC_EVENT_SETUP;
memcpy(&uvc_event->req,ctrl,sizeof(uvc_event->req));
v4l2_event_queue(&uvc->vdev,&v4l2_event);

return0;
}

4. 总结

15eed522-5ae6-11ee-939d-92fbcf53809c.png

整个bulk 传输控制流程如上图所示。

对于linux 平台而言,需要关心的有两点:1)如何将底层clear_halt 请求 与uvc_function 请求关联上,而不影响其他端点;2)如何将clear_halt 请求提交到应用层去处理。这一步不是非必须的。

对于Rtos 平台大同小异,只要理解了整个开关流流程,处理起来自然简单许多。

审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 接口
    +关注

    关注

    33

    文章

    7639

    浏览量

    148495
  • usb
    usb
    +关注

    关注

    59

    文章

    7432

    浏览量

    258173
  • Bulk
    +关注

    关注

    0

    文章

    8

    浏览量

    8605
  • uvc
    uvc
    +关注

    关注

    1

    文章

    122

    浏览量

    14334

原文标题:UVC Bulk 传输实现细节

文章出处:【微信号:漫谈嵌入式,微信公众号:漫谈嵌入式】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    关于FX3使用4个线程进行FPGA到USB的数据传输-状态机设置的问题求解

    我现在使用FX3来实现FPGA到上位机的数据传输,在使用2个线程用类似于UVC实例中的乒乓机制传输时没有问题。我看到GPIF II最多支持4个线程,所以想试一下4个线程的数据
    发表于 02-27 06:40

    请问Bulk传输是否可以被Interrupt传输打断?

    我用win10电脑与FX3设备进行通信,需要用Bulk传输从FX3读取大批量数据,但同时每100ms需用Interrupt EP去读取少量数据,驱动使用的Cypress的。 想问一下Bulk
    发表于 02-28 06:13

    请问FX3可以实现SlaveFifoSync+UVC吗?

    想让FX3实现SlaveFifoSync+UVC,具体是: FPGA将产生的视频数据以SlaveFifoSync方式传输给FX3,FX3再以UVC方式发送给上位机。 请问这样如何
    发表于 02-28 07:18

    使用AN75779进行UVC传输的时候,在上位机端实时传输会有图像帧丢失的原因?

    我在使用AN75779进行UVC传输的时候,发现在上位机端(virtualDub软件和ampcap以及我们自己编写的DirectShow程序)实时传输的时候偶尔会有图像帧丢失。丢失的频率在不同的电脑
    发表于 02-28 06:12

    AN75779 FX3 + UVC切换到异步模式时丢失数据的原因?

    我和我的团队正在TLE9243QK_BASE_BOARDAN75779 源代码上开发自定义 FX3 + UVC 应用程序 ,并在尝试实现同步通信时遇到问题。 到目前为止,我们按照KBA231897中
    发表于 03-06 07:19

    请问如何在STM32F407的USB_MSC例程上实现USB_OTG_FS与PC之间的bulk模式传输数据

    本人利用cube生成的USB_MSC(设备模式)的工程,如何在STM32F407的USB_MSC例程上修改以实现USB_OTG_FS与PC之间的bulk模式传输数据,请做过的大侠指导一下~
    发表于 02-14 07:00

    基于FPGA+USB3.0的UVC Camera实现方案

    `基于FPGA+USB3.0的UVC Camera实现方案AT7_Xilinx开发板(USB3.0+LVDS)资料共享腾讯链接:https://share.weiyun.com/5GQyKKc1
    发表于 03-18 17:16

    PC处理速度UVC数据太低?

    大家好!在CyPress FX3上成功完成了YUV格式数据UVC批量模式的传输,通过打印每秒DMABUF计数,测试了数据传输速度,最大可达200 Mb/s。ARG:最大突发大小=16DMABUF大小
    发表于 04-25 09:47

    如何使用cyfxuvcinmem_bulk示例?

    传输是否在Windows 8上工作。谢谢,亨利 以上来自于百度翻译 以下为原文Hi,I compiled cyfxuvcinmem_bulk which is one of the two
    发表于 05-09 09:34

    USB_BULK传输音频文件后不能用MCASP播放

    因为课题需要,想实现USB_bulk传输接受到音频数据文件后,然后将用查询的方式将数据播放出来,但是实际操作发现,一直卡在MCASP的发送上了,不知道该怎么解决,我的主函数如下:int main
    发表于 09-03 06:24

    【每日一知识点】在STM32F4上OTG 主机库在 BULK 传输上对 NAK 的处理

    问题:某客户使用 STM32F4 的 OTG 库做 USB 主机控制 Wifi 网卡。使用 BULK 传输类型时,从数据读取数据时,如果设备返回需要把设备返回的 NAK 状态告知上层应用,该如何修改
    发表于 06-02 15:22

    基于STM32F105实现USB-BULK传输

    基于STM32F105 实现USB-BULK传输由于项目需要,需要USB来传输,之前试的HID模式是已经调通,HID基于中断传输,一毫秒侦测
    发表于 08-18 06:05

    请问STM32F105如何实现USB BULK传输

    请问STM32F105如何实现USB BULK传输
    发表于 11-23 07:08

    07 Bulk设备

    07 Bulk设备
    发表于 10-11 09:19 6次下载
    07 <b class='flag-5'>Bulk</b>设备

    如何使用luvcview来实现UVC双摄像头拍摄

    Ubuntu下使用测试UVC 摄像头的工具有luvcview、mplayer等,我们就来介绍如何使用luvcview来实现UVC双摄像头拍摄。
    的头像 发表于 10-30 14:35 9314次阅读