uvc摄像头代码解析7
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__));
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;
}
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;
}
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, //轮询方法
};
struct uvc_fh {//uvc句柄
struct uvc_video_chain *chain; //uvc视频链
struct uvc_streaming *stream; //uvc视频流
enum uvc_handle_state state;
};
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;
}
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 控制方法
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
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 开始视频显示函数
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;
}
a.1 uvc视频流使能
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初始化视频
}
a.1.1 uvc使能队列
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;
}
a.1.2 uvc提交视频参数
int uvc_commit_video(struct uvc_streaming *stream,struct uvc_streaming_control *probe)
{
return uvc_set_video_ctrl(stream, probe, 0); //uvc设置视频控制
}
a.1.3 uvc初始化视频
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;
}
a.1.3.1 同步方式
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;
}
a.1.3.2 Bluk方式
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;
}
a.1.3.1 同步方式和a.1.3.2 Bluk方式 两种方式初始化uvc视频主要是分配设置urb,然后在uvc_init_video函数中又通过usb_submit_urb提交了urb,
两种方法的urb回调函数都是uvc_video_complete
a.2 urb回调函数uvc_video_complete
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);
}
}
对于同步和bilk方式的decode方法分别是
stream->decode = uvc_video_decode_isoc
stream->decode = uvc_video_encode_bulk;
这个在前面uvc_video_init函数中设置了
ok后面就开始解码了
uvc摄像头代码解析7的更多相关文章
- uvc摄像头代码解析1
一.FAQ 1.判断自己的摄像头是否支持uvc标准 输入lsusb //列出usb设备 [cpp] Bus 001 Device 001: ID 1d6b:0002 Linux Foundatio ...
- uvc摄像头代码解析5
8.初始化uvc控制 8.1 重要结构体 struct uvc_control { //uvc控制 struct uvc_entity *entity; //uvc实体 struct uvc_cont ...
- uvc摄像头代码解析6
10.扫描视频设备链和注册视频设备 10.1 uvc视频链 struct uvc_video_chain { //uvc视频链 struct uvc_device *dev; //uvc设备 stru ...
- c#专业的UVC摄像头深控类库-SharpCamera介绍
SharpCamera是专业的UVC摄像头深控类库.允许您在C#代码内修改摄像头的高级参数,比如亮度.对比度.清晰度.色调.饱和度.伽玛值.白平衡.逆光对比.增益.缩放.焦点.曝光.光圈.全景.倾斜. ...
- C#控制操控操作多个UVC摄像头设备
有时,我们需要在C#代码中对多个UVC摄像头进行操作,如何实现呢? 建立基于SharpCamera的项目 首先,请根据之前的一篇博文 点击这里 中的说明,建立基于SharpCamera的摄像头控制项目 ...
- C#采集UVC摄像头画面并支持旋转和分辨率切换
在项目中,我们会需要控制uvc摄像头,采集其实时画面,或者对其进行旋转.目前市面上大多数USB摄像头都支持UVC协议.那么如何采集呢?当然是采用SharpCamera!因为SharpCamera支持对 ...
- VBA常用代码解析
031 删除工作表中的空行 如果需要删除工作表中所有的空行,可以使用下面的代码. Sub DelBlankRow() DimrRow As Long DimLRow As Long Dimi As L ...
- [nRF51822] 12、基础实验代码解析大全 · 实验19 - PWM
一.PWM概述: PWM(Pulse Width Modulation):脉冲宽度调制技术,通过对一系列脉冲的宽度进行调制,来等效地获得所需要波形. PWM 的几个基本概念: 1) 占空比:占空比是指 ...
- [nRF51822] 11、基础实验代码解析大全 · 实验16 - 内部FLASH读写
一.实验内容: 通过串口发送单个字符到NRF51822,NRF51822 接收到字符后将其写入到FLASH 的最后一页,之后将其读出并通过串口打印出数据. 二.nRF51822芯片内部flash知识 ...
随机推荐
- CSS的三种样式:内联式,嵌入式,外部式以及他们的优先级
从CSS 样式代码插入的形式来看基本能够分为下面3种:内联式.嵌入式和外部式三种. 1:内联式css样式表就是把css代码直接写在现有的HTML标签中,如以下代码: <p style=" ...
- iOS开发中NSDate时间戳的转换--
NSTimeInterval time =(NSTimeInterval )[model.day floatValue]; NSDate *date = [NSDate dateWithTimeInt ...
- Cpu实验
实验十一.基于符合ISO/IEC 7816 标准协议的CPU卡RATS.PPS请求指令操作 实验目的 1.学习和了解ISO/IEC 7816标准. 2.学习和了解ATS各字节的具体定义. 3.学习和了 ...
- JVM 指令集合
指令码 助记符 说明 0x00 nop 什么都不做 0x01 aconst_null 将null推送至栈顶 0x02 iconst_m1 将int型-1推送至栈顶 0x03 iconst_0 将int ...
- 使用 getopt() 进行命令行处理
引言 在早期的 UNIX® 中,其命令行环境(当时的唯一用户界面)包含着数十种小的文本处理工具.这些工具非常小,通常可很好地完成一项工作.这些工具通过较长的命令管道链接在一起,前面的程序将其输出传递给 ...
- 鼠标滑轮一滚动Excel就停止工作
鼠标滑轮一滚动Excel就停止工作 问题签名: 问题事件名称:APPCRASH 应用程序名:EXCEL.EXE 应用程序版本:15.0.4420.1017 应用程序时间戳:50673286 故障模块名 ...
- 最简单也最难——如何获取到Android控件的高度
问题 如何获取一个控件的长和高,相信很多朋友第一眼看见这个问题都会觉得很简单,直接在onCreate里面调用getWidth.getMeasuredWidth不就可以获得了吗,但是,事实上是并没有简单 ...
- BT基础知识简介
1. 蓝牙概述 无线局域网的通信 适用范围:10米到100米(根据发射功率的class不同有所差别,典型的class2为10m,而class1为100m,class3为1m) 应用: 局域网络 ...
- java--局部类只能访问外包方法的final局部成员
class B523{ // private int k = 10; public void go(int x, final int y){ // int a = x+y; final int b = ...
- Windows Service的官方描述,抄下来(不写obj就是LocalSystem)
How to create a Windows service by using Sc.exe Email Print Support for Windows XP has ended Micro ...