• (七) UVC框架分析



    title: UVC框架分析
    date: 2019/4/23 19:50:00
    toc: true

    UVC框架分析

    源码的位置在driversmediavideouvc,查看下Makefile,我们可以从入口uvc_driver.c中分析

    uvcvideo-objs  := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o 
                      uvc_status.o uvc_isight.o uvc_debugfs.o
    ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
    uvcvideo-objs  += uvc_entity.o
    endif
    obj-$(CONFIG_USB_VIDEO_CLASS) += uvcvideo.o
    

    入口函数

    module_init(uvc_init);
    	>usb_register(&uvc_driver.driver)
    	
    struct uvc_driver uvc_driver = {
    	.driver = {
    		.name		= "uvcvideo",
    		.probe		= uvc_probe,
    		.disconnect	= uvc_disconnect,
    		.suspend	= uvc_suspend,
    		.resume		= uvc_resume,
    		.reset_resume	= uvc_reset_resume,
    		.id_table	= uvc_ids,
    		.supports_autosuspend = 1,
    	},
    };
    

    这里的id_table表示能够支持哪些设备,probe表示匹配到之后执行probe函数

    uvc_probe

    uvc_register_chains
    	uvc_register_terms
    		uvc_register_video
    			uvc_video_init
    			// 这里就是以前vivi中讲的 设置
    			video_device_alloc
    			vdev->v4l2_dev = &dev->vdev;
    			vdev->fops = &uvc_fops;
    			vdev->release = uvc_release;
    			strlcpy(vdev->name, dev->name, sizeof vdev->name);
    			//注册
    			video_register_device(vdev, VFL_TYPE_GRABBER, -1);
    

    文件ops

    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,
    
    };
    

    UVC规格书一览

    搜索下uvc Specification,链接在此,主要是USB_Video_Example 1.5.pdfUVC 1.5 Class specification.pdf

    先来看下USB_Video_Example 中的图

    mark

    再来看下规格书的基本描述,参考链接,这个unit实际上就是一个个内部的功能模块,terminal是用于连接内外的功能模块.

    Unit

    Unit提供了基础模块来全面描述大部分的视频功能,一个Unit可以由一个或多个输入引脚和仅一个输出引脚(这里的每一个pin代表一个逻辑上的数据流) ,Unit可以通过pin引脚连接在一起,一个输出pin可以连接多个输入pin,但一个输入pin只能连接一个输出pin

    mark

    Select Unit

    这个就是多路选择unit

    mark

    Processing Unit

    处理Unit (PU)控制流经它的视频流图像属性。
    User Controls

    • Brightness
    • Hue
    • Saturation
    • Sharpness
    • Gamma
    • Digital Multiplier (Zoom)

    Auto Controls

    • White Balance Temperature
    • White Balance Component
    • Backlight Compensation
    • Contrast
    • Other

    Gain

    • Power Line Frequency
    • Analog Video Standard
    • Analog Video Lock Status

    Terminal

    链接内外的功能模块,一个输入和一个输出

    • Input Terminal
    • Out Terminal
    • Camera Terminal 控制端点.有些设备可能没有
      • Scanning Mode扫描模式
      • Auto-Exposure Mode自动曝光模式
      • Auto-Exposure Priority自动曝光优先级
      • Exposure Time 曝光时间
      • Focus聚焦
      • Auto-Focus自动聚焦
      • Simple Focus简单聚焦
      • Iris红外
      • Zoom放大
      • Pan摇动
      • Roll滚动
      • Tilt倾斜
      • Digital Windowing数字窗口

    总的来说就是一个摄像头,一定会有起码1个的VS视频流接口,但不一定有vs控制接口.通过VideoControl Interface来控制,通过VideoStreaming Interface来读视频数据,VC里含有多个Unit/Terminal等功能模块,可以通过访问这些模块进行控制,比如调亮度

    APP使用UVC驱动过程

    uvc_register_chains
    	uvc_register_terms
    		uvc_register_video
    			uvc_video_init
    			// 这里就是以前vivi中讲的 设置
    			video_device_alloc
    			vdev->v4l2_dev = &dev->vdev;
    			vdev->fops = &uvc_fops;
    			vdev->release = uvc_release;
    			strlcpy(vdev->name, dev->name, sizeof vdev->name);
    			//注册
    			video_register_device(vdev, VFL_TYPE_GRABBER, -1);
    			
    			
    APP调用过程
    	open
    		uvc_v4l2_open
    	unlocked_ioctl
    		uvc_v4l2_ioctl
    			uvc_v4l2_do_ioctl
    				case VIDIOC_QUERYCAP:
    					.....
    					
    VIDIOC_QUERYCAP
    	//通过 stream->type 来设置,这个type 应该是在设备枚举时设置
    		if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
    			cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
    					  | V4L2_CAP_STREAMING;
    		else
    			cap->capabilities = V4L2_CAP_VIDEO_OUTPUT
    					  | V4L2_CAP_STREAMING;
    
    VIDIOC_ENUM_FMT
    	//通过 stream->format
    	format = &stream->format[fmt->index];
    VIDIOC_G_FMT
    	// USB摄像头支持多种格式fromat, 每种格式下有多种frame(比如分辨率)
    	uvc_v4l2_get_format(stream, arg)
    		format = stream->cur_format;
    		frame = stream->cur_frame;
    		fmt->fmt.pix.pixelformat = format->fcc;
    		fmt->fmt.pix.width = frame->wWidth; 
    		fmt->fmt.pix.height = frame->wHeight; 
    VIDIOC_TRY_FMT
    	uvc_v4l2_try_format(stream, arg, &probe, NULL, NULL)
    		/* Check if the hardware supports the requested format. */
    		// 根据 stream中的format 来比较
    		format = &stream->format[i]
    		if(format->fcc == fmt->fmt.pix.pixelformat)
    		/* Find the closest image size */
    		//找到最接近的图像大小
    VIDIOC_S_FMT
    	uvc_v4l2_set_format(stream, arg)
    		// 只是尝试把参数保存,并没有发起usb传输
    		uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame)
    
    VIDIOC_REQBUFS
    	uvc_alloc_buffers(&stream->queue, arg);
    		vb2_reqbufs(&queue->queue, rb);
    		
    VIDIOC_QUERYBUF
    	//查询buf
    	uvc_query_buffer
    		vb2_querybuf
    			__fill_v4l2_buffer
    mmap
    	uvc_v4l2_mmap
    		uvc_queue_mmap
    			vb2_mmap
    			
    VIDIOC_QBUF
    	uvc_queue_buffer
    		vb2_qbuf
    
    VIDIOC_STREAMON
    	uvc_video_enable // 把所设置的参数发给硬件,然后启动摄像头
    		uvc_queue_enable
    			vb2_streamon
    				q->streaming = 1;
    		/* Commit the streaming parameters. */
    		ret = uvc_commit_video(stream, &stream->ctrl);
    			uvc_set_video_ctrl /* 设置格式fromat, frame */
    				__uvc_query_ctrl
    					usb_control_msg //usb传输
    		//启动urb传输			
    		uvc_init_video
    			uvc_video_stats_start(stream);
    			
    			uvc_init_video_isoc
    					// 分配 设置 urb
    					uvc_alloc_urb_buffers
    					usb_fill_bulk_urb
    					urb->complete = uvc_video_complete;  // usb传输完成的函数,这里应该会去唤醒uvc驱动
    			/* Submit the URBs. */
    			usb_submit_urb
    urb传输完成函数.这里会有wakeup			
    uvc_video_complete
    	stream->decode(urb, stream, buf);  //此函数搜索下
    		stream->decode = uvc_video_decode_isight;
    		stream->decode = uvc_video_decode_isoc;
    			uvc_queue_next_buffer
    				vb2_buffer_done
    					wake_up(&q->done_wq);
    
    poll
    	uvc_v4l2_poll
    		uvc_queue_poll
    			vb2_poll
    				poll_wait(file, &q->done_wq, wait);
    						//这里会接着判断状态
    						if (vb && (vb->state == VB2_BUF_STATE_DONE
    						|| vb->state == VB2_BUF_STATE_ERROR)) {
    						return (V4L2_TYPE_IS_OUTPUT(q->type)) ? POLLOUT | POLLWRNORM :
    							POLLIN | POLLRDNORM;
    
    
    
    VIDIOC_DQBUF
            uvc_dequeue_buffer
            	vb2_dqbuf
    				list_del(&vb->queued_entry);
    
    VIDIOC_STREAMOFF            
            uvc_video_enable(video, 0);
    			uvc_uninit_video
    				usb_kill_urb(urb);
    				usb_free_urb(urb);
    
    分析设置亮度过程:
    ioctl: VIDIOC_S_CTRL
                uvc_ctrl_set
                uvc_ctrl_commit
                    __uvc_ctrl_commit(video, 0);
                        uvc_ctrl_commit_entity(video->dev, entity, rollback);
                    			ret = uvc_query_ctrl(dev  /* 哪一个USB设备 */, SET_CUR, ctrl->entity->id  /* 哪一个unit/terminal */,
                    				dev->intfnum /* 哪一个接口: VC interface */, ctrl->info->selector,
                    				uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
                    				ctrl->info->size);
    
    
    
    

    小结

    1. UVC设备有2个interface: VideoControl Interface, VideoStreaming Interface
    2. VideoControl Interface用于控制,比如设置亮度。它内部有多个Unit/Terminal(在程序里Unit/Terminal都称为entity)
       可以通过类似的函数来访问:
                    			ret = uvc_query_ctrl(dev  /* 哪一个USB设备 */, SET_CUR, ctrl->entity->id  /* 哪一个unit/terminal */,
                    				dev->intfnum /* 哪一个接口: VC interface */, ctrl->info->selector,
                    				uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
                    				ctrl->info->size);
    3. VideoStreaming Interface用于获得视频数据,也可以用来选择fromat/frame(VS可能有多种format, 一个format支持多种frame, frame用来表示分辨率等信 息)
       可以通过类似的函数来访问:
                        	ret = __uvc_query_ctrl(video->dev /* 哪一个USB设备 */, SET_CUR, 0,
                        		video->streaming->intfnum  /* 哪一个接口: VS */,
                        		probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size,
                        		uvc_timeout_param);
    4. 我们在设置FORMAT时只是简单的使用video->streaming->format[fmt->index]等数据,
       这些数据哪来的?
       应是设备被枚举时设置的,也就是分析它的描述符时设置的。
    
    5. UVC驱动的重点在于:
       描述符的分析
       属性的控制: 通过VideoControl Interface来设置
       格式的选择:通过VideoStreaming Interface来设置
       数据的获得:通过VideoStreaming Interface的URB来获得
    
  • 相关阅读:
    邻项交换排序
    [POJ 2559]Largest Rectangle in a Histogram 单调栈
    最大子序和 单调队列
    单调栈 总结
    计算中缀表达式
    [HYSBZ 2457] 双端队列
    数组的宽度 单调栈
    SVM从入门到精通
    CVPR2018_RotationNet: Joint Object Categorization and Pose Estimation Using Multiviews from Unsupervised Viewpoints
    比特币以及区块链入门
  • 原文地址:https://www.cnblogs.com/zongzi10010/p/10764246.html
Copyright © 2020-2023  润新知