13.uvc视频初始化
13.1 uvc数据流控制
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__));
13.2 uvc_video_init
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;
}
13.2.1 初始化uvc队列
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;
}
14.uvc V4L2设备
14.1 V4L2操作函数集
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, //轮询方法
};
14.2 打开方法
14.2.1 相关结构体
struct uvc_fh {//uvc句柄
struct uvc_video_chain *chain; //uvc视频链
struct uvc_streaming *stream; //uvc视频流
enum uvc_handle_state state;
};
14.2.2 open
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;
}
14.2.2.1 uvc_status_start启动状态
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 控制方法

14.3.1 V4L2的控制方式可以参考下面的资料
linux媒体接口API
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的更多相关文章

  1. uvc摄像头代码解析1

    一.FAQ 1.判断自己的摄像头是否支持uvc标准 输入lsusb //列出usb设备 [cpp]   Bus 001 Device 001: ID 1d6b:0002 Linux Foundatio ...

  2. uvc摄像头代码解析5

    8.初始化uvc控制 8.1 重要结构体 struct uvc_control { //uvc控制 struct uvc_entity *entity; //uvc实体 struct uvc_cont ...

  3. uvc摄像头代码解析6

    10.扫描视频设备链和注册视频设备 10.1 uvc视频链 struct uvc_video_chain { //uvc视频链 struct uvc_device *dev; //uvc设备 stru ...

  4. c#专业的UVC摄像头深控类库-SharpCamera介绍

    SharpCamera是专业的UVC摄像头深控类库.允许您在C#代码内修改摄像头的高级参数,比如亮度.对比度.清晰度.色调.饱和度.伽玛值.白平衡.逆光对比.增益.缩放.焦点.曝光.光圈.全景.倾斜. ...

  5. C#控制操控操作多个UVC摄像头设备

    有时,我们需要在C#代码中对多个UVC摄像头进行操作,如何实现呢? 建立基于SharpCamera的项目 首先,请根据之前的一篇博文 点击这里 中的说明,建立基于SharpCamera的摄像头控制项目 ...

  6. C#采集UVC摄像头画面并支持旋转和分辨率切换

    在项目中,我们会需要控制uvc摄像头,采集其实时画面,或者对其进行旋转.目前市面上大多数USB摄像头都支持UVC协议.那么如何采集呢?当然是采用SharpCamera!因为SharpCamera支持对 ...

  7. VBA常用代码解析

    031 删除工作表中的空行 如果需要删除工作表中所有的空行,可以使用下面的代码. Sub DelBlankRow() DimrRow As Long DimLRow As Long Dimi As L ...

  8. [nRF51822] 12、基础实验代码解析大全 · 实验19 - PWM

    一.PWM概述: PWM(Pulse Width Modulation):脉冲宽度调制技术,通过对一系列脉冲的宽度进行调制,来等效地获得所需要波形. PWM 的几个基本概念: 1) 占空比:占空比是指 ...

  9. [nRF51822] 11、基础实验代码解析大全 · 实验16 - 内部FLASH读写

     一.实验内容: 通过串口发送单个字符到NRF51822,NRF51822 接收到字符后将其写入到FLASH 的最后一页,之后将其读出并通过串口打印出数据. 二.nRF51822芯片内部flash知识 ...

随机推荐

  1. Codeforces 360C Levko and Strings dp

    题目链接:点击打开链接 题意: 给定长度为n的字符串s,常数k 显然s的子串一共同拥有 n(n-1)/2 个 要求找到一个长度为n的字符串t,使得t相应位置的k个子串字典序>s #include ...

  2. FragmentPagerAdapter刷新fragment最完美解决方案

    FragmentPagerAdapter刷新fragment最完美解决方案   先感谢kingjxl2006的博客文章<Android FragmentPagerAdapter数据刷新notif ...

  3. load、save方法、spark sql的几种数据源

    load.save方法的用法          DataFrame usersDF = sqlContext.read().load("hdfs://spark1:9000/users.pa ...

  4. c++,命名空间(namespace)

    1.什么是命名空间: 命名空间:实际上就是一个由程序设计者命名的内存区域,程序设计者可以根据需要指定一些有名字的空间域,把一些全局实体分别放在各个命名空间中,从而与其他全局实体分隔开来. 2.命名空间 ...

  5. 查锁住的表,以及kill进程,Oracle常用语句

    --找出所有被锁的对象,定位出哪个回话占用 select l.session_id,o.owner,o.object_name from v$locked_object l,dba_objects o ...

  6. datetime.timedelta

    from django.utils import timezoneimport datetime timezone.now()datetime.datetime(2014, 7, 18, 9, 42, ...

  7. 基于Sql Server 2008的分布式数据库的实践(二)

    原文 基于Sql Server 2008的分布式数据库的实践(二) 从Win7连接Win2003的Sql Server 2008 1.新建链接服务器链接到Win2003的Sql Server 2008 ...

  8. 基于visual Studio2013解决C语言竞赛题之0605strcat

      题目

  9. 2014Esri全球用户大会之标准和互操作

    1.   ArcGIS是一个开放协作的平台吗?Esri是怎样看待"开放"的? 是的,ArcGIS是一个开放协作的平台.Esri公司致力于支持我们的用户更加easy的在异构环境下工作 ...

  10. linux stat系统调用,获取文件信息。

    stat 函数原型: int stat(const char *path, struct stat *buf); struct stat 说明 struct stat { mode_t st_mode ...