uvc摄像头代码解析7

转http://blog.csdn.net/orz415678659/article/details/10083585


13.uvc视频初始化
13.1 uvc数据流控制
[cpp]  view plain  copy
  1. struct uvc_streaming_control {  
  2.     __u16 bmHint;  
  3.     __u8  bFormatIndex; //视频格式索引  
  4.     __u8  bFrameIndex;  //视频帧索引  
  5.     __u32 dwFrameInterval;  //视频帧间隔  
  6.     __u16 wKeyFrameRate;    //  
  7.     __u16 wPFrameRate;  
  8.     __u16 wCompQuality;  
  9.     __u16 wCompWindowSize;  
  10.     __u16 wDelay;   //延时  
  11.     __u32 dwMaxVideoFrameSize;  //最大视频帧大小  
  12.     __u32 dwMaxPayloadTransferSize;  
  13.     __u32 dwClockFrequency; //时钟频率  
  14.     __u8  bmFramingInfo;  
  15.     __u8  bPreferedVersion;  
  16.     __u8  bMinVersion;  //版本  
  17.     __u8  bMaxVersion;  //版本  
  18. } __attribute__((__packed__));  
13.2 uvc_video_init
[cpp]  view plain  copy
  1. int uvc_video_init(struct uvc_streaming *stream)  
  2. {  
  3.     struct uvc_streaming_control *probe = &stream->ctrl; //获取uvc数据流的uvs数据流控制对象  
  4.     struct uvc_format *format = NULL;  
  5.     struct uvc_frame *frame = NULL;  
  6.     unsigned int i;  
  7.     int ret;  
  8.     if (stream->nformats == 0) {  
  9.         uvc_printk(KERN_INFO, "No supported video formats found.\n");  
  10.         return -EINVAL;  
  11.     }  
  12.     atomic_set(&stream->active, 0);  
  13.     uvc_queue_init(&stream->queue, stream->type, !uvc_no_drop_param); //初始化视频缓冲区队列  
  14.     usb_set_interface(stream->dev->udev, stream->intfnum, 0);  //选择Alt.Setting 0  
  15.     if (uvc_get_video_ctrl(stream, probe, 1, UVC_GET_DEF) == 0) //VS_PROBE_CONTROL(GET_DEF)  
  16.         uvc_set_video_ctrl(stream, probe, 1);                   //VS_PROBE_CONTROL(SET_DEF)  
  17.     ret = uvc_get_video_ctrl(stream, probe, 1, UVC_GET_CUR);    //VS_PROBE_CONTROL(GET_CUR)  
  18.     if (ret < 0)  
  19.         return ret;  
  20.     for (i = stream->nformats; i > 0; --i) {  //获取对应的uvc格式  
  21.         format = &stream->format[i-1];     
  22.         if (format->index == probe->bFormatIndex) //匹配uvc格式索引值  
  23.             break;  
  24.     }  
  25.     if (format->nframes == 0) {  
  26.         uvc_printk(KERN_INFO, "No frame descriptor found for the default format.\n");  
  27.         return -EINVAL;  
  28.     }  
  29.     for (i = format->nframes; i > 0; --i) {  
  30.         frame = &format->frame[i-1]; //获取对应的uvc帧  
  31.         if (frame->bFrameIndex == probe->bFrameIndex) //匹配uvc帧索引值  
  32.             break;  
  33.     }  
  34.     probe->bFormatIndex = format->index;      //设置uvc视频流控制的格式索引为uvc格式的索引  
  35.     probe->bFrameIndex = frame->bFrameIndex;  //设置uvc视频流控制的帧索引为uvc帧的索引  
  36.     stream->cur_format = format;             //设置uvc格式为uvc数据流的cur_format成员  
  37.     stream->cur_frame = frame;                   //设置uvc帧未uvc数据流的cur_frame成员  
  38.     /* Select the video decoding function 选择视频解码函数*/  
  39.     if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {   //视频采集  
  40.         if (stream->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)  
  41.             stream->decode = uvc_video_decode_isight;  
  42.         else if (stream->intf->num_altsetting > 1)  
  43.             stream->decode = uvc_video_decode_isoc;  //同步方式  
  44.         else  
  45.             stream->decode = uvc_video_decode_bulk;  //bluk方式  
  46.     }   
  47.     else {  //视频播放  
  48.         if (stream->intf->num_altsetting == 1)  
  49.             stream->decode = uvc_video_encode_bulk;  
  50.         else {  
  51.             uvc_printk(KERN_INFO, "Isochronous endpoints are not supported for video output devices.\n");  
  52.             return -EINVAL;  
  53.         }  
  54.     }  
  55.     return 0;  
  56. }  
13.2.1 初始化uvc队列
[cpp]  view plain  copy
  1. void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,int drop_corrupted)  
  2. {  
  3.     mutex_init(&queue->mutex);  
  4.     spin_lock_init(&queue->irqlock);  
  5.     INIT_LIST_HEAD(&queue->mainqueue);   //初始化uvc视频队列mainqueue链表  
  6.     INIT_LIST_HEAD(&queue->irqqueue);    //初始化uvc视频队列irqqueue链表  
  7.     queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0;  
  8.     queue->type = type;  
  9. }  

14.uvc V4L2设备
14.1 V4L2操作函数集
[cpp]  view plain  copy
  1. const struct v4l2_file_operations uvc_fops = {  
  2.     .owner      = THIS_MODULE,  
  3.     .open       = uvc_v4l2_open,    //打开方法  
  4.     .release             = uvc_v4l2_release,    //释放方法  
  5.     .unlocked_ioctl = uvc_v4l2_ioctl,   //控制方法  
  6.     .read       = uvc_v4l2_read,    //读方法  
  7.     .mmap       = uvc_v4l2_mmap,    //映射方法  
  8.     .poll       = uvc_v4l2_poll,    //轮询方法  
  9. };  
14.2 打开方法
14.2.1 相关结构体
[cpp]  view plain  copy
  1. struct uvc_fh {//uvc句柄  
  2.     struct uvc_video_chain *chain;  //uvc视频链  
  3.     struct uvc_streaming *stream;   //uvc视频流  
  4.     enum uvc_handle_state state;  
  5. };  
14.2.2 open
[cpp]  view plain  copy
  1. static int uvc_v4l2_open(struct file *file)  
  2. {  
  3.     struct uvc_streaming *stream;  
  4.     struct uvc_fh *handle;  
  5.     int ret = 0;  
  6.   
  7.     uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n");  
  8.     stream = video_drvdata(file);   //获取uvc视频流  
  9.     if (stream->dev->state & UVC_DEV_DISCONNECTED)    //设备没连接  
  10.         return -ENODEV;  
  11.     ret = usb_autopm_get_interface(stream->dev->intf);    //唤醒设备  
  12.     if (ret < 0)  
  13.         return ret;  
  14.     /* Create the device handle. */  
  15.     handle = kzalloc(sizeof *handle, GFP_KERNEL);   //创建uvc句柄  
  16.     if (handle == NULL) {  
  17.         usb_autopm_put_interface(stream->dev->intf);  
  18.         return -ENOMEM;  
  19.     }  
  20.     if (atomic_inc_return(&stream->dev->users) == 1) {  
  21.         ret = uvc_status_start(stream->dev); //uvc状态开始  
  22.         if (ret < 0) {  
  23.             usb_autopm_put_interface(stream->dev->intf);  
  24.             atomic_dec(&stream->dev->users);  
  25.             kfree(handle);  
  26.             return ret;  
  27.         }  
  28.     }  
  29.     handle->chain = stream->chain;    //捆绑uvc句柄和uvc视频链  
  30.     handle->stream = stream; //捆绑uvc句柄和uvc视频流  
  31.     handle->state = UVC_HANDLE_PASSIVE;  //设置uvc状态为未激活  
  32.     file->private_data = handle; //将uvc句柄作为文件的私有数据  
  33.     return 0;  
  34. }  
14.2.2.1 uvc_status_start启动状态
[cpp]  view plain  copy
  1. int uvc_status_start(struct uvc_device *dev)  
  2. {  
  3.     if (dev->int_urb == NULL)  
  4.         return 0;  
  5.     return usb_submit_urb(dev->int_urb, GFP_KERNEL); //提交urb  
  6. }  
参看 12.uvc状态初始化
14.3 控制方法
14.3.1 V4L2的控制方式可以参考下面的资料
linux媒体接口API
[cpp]  view plain  copy
  1. VIDIOC_REQBUFS:分配内存   
  2. VIDIOC_QUERYBUF:把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址   
  3. VIDIOC_QUERYCAP:查询驱动功能   
  4. VIDIOC_ENUM_FMT:获取当前驱动支持的视频格式   
  5. VIDIOC_S_FMT:设置当前驱动的频捕获格式   
  6. VIDIOC_G_FMT:读取当前驱动的频捕获格式   
  7. VIDIOC_TRY_FMT:验证当前驱动的显示格式   
  8. VIDIOC_CROPCAP:查询驱动的修剪能力   
  9. VIDIOC_S_CROP:设置视频信号的边框   
  10. VIDIOC_G_CROP:读取视频信号的边框   
  11. VIDIOC_QBUF:把数据从缓存中读取出来   
  12. VIDIOC_DQBUF:把数据放回缓存队列   
  13. VIDIOC_STREAMON:开始视频显示函数   
  14. VIDIOC_STREAMOFF:结束视频显示函数   
  15. VIDIOC_QUERYSTD:检查当前视频设备支持的标准,例如PAL或NTSC。   
14.3.2 uvc设备V4L2控制方法uvc_v4l2_do_ioctl
[cpp]  view plain  copy
  1. static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)  
  2. {  
  3.     struct video_device *vdev = video_devdata(file);//获取V4L2设备  
  4.     struct uvc_fh *handle = file->private_data;//获取uvc句柄  
  5.     struct uvc_video_chain *chain = handle->chain;//获取uvc视频链  
  6.     struct uvc_streaming *stream = handle->stream;//获取uvc视频流  
  7.     long ret = 0;  
  8.   
  9.     switch (cmd) {  
  10.     ...  
  11.     case ...:  
  12.     {  
  13.         ...  
  14.         break;  
  15.     }  
  16.     return ret;  
  17. }  
a.VIDIOC_STREAMON 开始视频显示函数
[cpp]  view plain  copy
  1. case VIDIOC_STREAMON:  
  2. {  
  3.     int *type = arg;  
  4.     if (*type != stream->type)  
  5.         return -EINVAL;  
  6.     if (!uvc_has_privileges(handle))  
  7.         return -EBUSY;  
  8.     mutex_lock(&stream->mutex);  
  9.     ret = uvc_video_enable(stream, 1);  //uvc视频流使能  
  10.     mutex_unlock(&stream->mutex);  
  11.     if (ret < 0)  
  12.         return ret;  
  13.     break;  
  14. }  
a.1 uvc视频流使能
[cpp]  view plain  copy
  1. int uvc_video_enable(struct uvc_streaming *stream, int enable)  
  2. {  
  3.     int ret;  
  4.     if (!enable) {  
  5.         uvc_uninit_video(stream, 1);//逆初始化视频  
  6.         usb_set_interface(stream->dev->udev, stream->intfnum, 0);  
  7.         uvc_queue_enable(&stream->queue, 0);//uvc禁用队列  
  8.         return 0;  
  9.     }  
  10.     ret = uvc_queue_enable(&stream->queue, 1);   //uvc使能队列  
  11.     if (ret < 0)  
  12.         return ret;  
  13.     /* Commit the streaming parameters. */  
  14.     ret = uvc_commit_video(stream, &stream->ctrl);   //uvc提交视频参数  
  15.     if (ret < 0)  
  16.         return ret;  
  17.     return uvc_init_video(stream, GFP_KERNEL);  //uvc初始化视频  
  18. }  
a.1.1 uvc使能队列
[cpp]  view plain  copy
  1. static int uvc_queue_enable(struct uvc_video_queue *queue, int enable)  
  2. {  
  3.     unsigned int i;  
  4.     int ret = 0;  
  5.     mutex_lock(&queue->mutex);  
  6.     if (enable) {   //使能uvc队列  
  7.         if (uvc_queue_streaming(queue)) {   //判断队列标志是否为UVC_QUEUE_STREAMING  
  8.             ret = -EBUSY;  
  9.             goto done;  
  10.         }  
  11.         queue->sequence = 0;  
  12.         queue->flags |= UVC_QUEUE_STREAMING; //设置队列标志  
  13.         queue->buf_used = 0; //设置缓冲区使用标志  
  14.     }   
  15.     else {  
  16.         uvc_queue_cancel(queue, 0); //取消uvc队列  
  17.         INIT_LIST_HEAD(&queue->mainqueue);   //重新初始化uvc队列mainqueue队列头  
  18.         for (i = 0; i < queue->count; ++i)  
  19.             queue->buffer[i].state = UVC_BUF_STATE_IDLE; //设置缓冲区状态为闲置态  
  20.         queue->flags &= ~UVC_QUEUE_STREAMING;    //设置队列标志  
  21.     }  
  22. done:  
  23.     mutex_unlock(&queue->mutex);  
  24.     return ret;  
  25. }  
a.1.2 uvc提交视频参数
[cpp]  view plain  copy
  1. int uvc_commit_video(struct uvc_streaming *stream,struct uvc_streaming_control *probe)  
  2. {  
  3.     return uvc_set_video_ctrl(stream, probe, 0);    //uvc设置视频控制  
  4. }  
a.1.3 uvc初始化视频
[cpp]  view plain  copy
  1. static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)  
  2. {  
  3.     struct usb_interface *intf = stream->intf;  
  4.     struct usb_host_endpoint *ep;  
  5.     unsigned int i;  
  6.     int ret;  
  7.     stream->sequence = -1;  
  8.     stream->last_fid = -1;  
  9.     stream->bulk.header_size = 0;  
  10.     stream->bulk.skip_payload = 0;  
  11.     stream->bulk.payload_size = 0;  
  12.     if (intf->num_altsetting > 1) {   //同步方式  
  13.         struct usb_host_endpoint *best_ep = NULL;  
  14.         unsigned int best_psize = 3 * 1024;  
  15.         unsigned int bandwidth;  
  16.         unsigned int uninitialized_var(altsetting);  
  17.         int intfnum = stream->intfnum;  
  18.         /* Isochronous endpoint, select the alternate setting. */  
  19.         bandwidth = stream->ctrl.dwMaxPayloadTransferSize;  
  20.         if (bandwidth == 0) {  
  21.             uvc_trace(UVC_TRACE_VIDEO, "Device requested null bandwidth, defaulting to lowest.\n");  
  22.             bandwidth = 1;  
  23.         }   
  24.         else {  
  25.             uvc_trace(UVC_TRACE_VIDEO, "Device requested %u B/frame bandwidth.\n", bandwidth);  
  26.         }  
  27.         for (i = 0; i < intf->num_altsetting; ++i) {  
  28.             struct usb_host_interface *alts;  
  29.             unsigned int psize;  
  30.             alts = &intf->altsetting[i];  
  31.             ep = uvc_find_endpoint(alts,stream->header.bEndpointAddress);  
  32.             if (ep == NULL)  
  33.                 continue;  
  34.             /* Check if the bandwidth is high enough. */  
  35.             psize = le16_to_cpu(ep->desc.wMaxPacketSize);  
  36.             psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));  
  37.             if (psize >= bandwidth && psize <= best_psize) {  
  38.                 altsetting = i;  
  39.                 best_psize = psize;  
  40.                 best_ep = ep;  
  41.             }  
  42.         }  
  43.         if (best_ep == NULL) {  
  44.             uvc_trace(UVC_TRACE_VIDEO, "No fast enough alt setting for requested bandwidth.\n");  
  45.             return -EIO;  
  46.         }  
  47.         uvc_trace(UVC_TRACE_VIDEO, "Selecting alternate setting %u (%u B/frame bandwidth).\n", altsetting, best_psize);  
  48.         ret = usb_set_interface(stream->dev->udev, intfnum, altsetting);  
  49.         if (ret < 0)  
  50.             return ret;  
  51.         ret = uvc_init_video_isoc(stream, best_ep, gfp_flags);  //uvc初始化视频(同步方法)  
  52.     }   
  53.     else {  //Bulk方式  
  54.         /* Bulk endpoint, proceed to URB initialization. */  
  55.         ep = uvc_find_endpoint(&intf->altsetting[0],stream->header.bEndpointAddress);  
  56.         if (ep == NULL)  
  57.             return -EIO;  
  58.         ret = uvc_init_video_bulk(stream, ep, gfp_flags);   //uvc初始化视频(bulk方法)  
  59.     }  
  60.     if (ret < 0)  
  61.         return ret;  
  62.     /* Submit the URBs. */  
  63.     for (i = 0; i < UVC_URBS; ++i) {  
  64.         ret = usb_submit_urb(stream->urb[i], gfp_flags); //提交urb  
  65.         if (ret < 0) {  
  66.             uvc_printk(KERN_ERR, "Failed to submit URB %u (%d).\n", i, ret);  
  67.             uvc_uninit_video(stream, 1);  
  68.             return ret;  
  69.         }  
  70.     }  
  71.   
  72.     return 0;  
  73. }  
a.1.3.1 同步方式
[cpp]  view plain  copy
  1. static int uvc_init_video_isoc(struct uvc_streaming *stream,struct usb_host_endpoint *ep, gfp_t gfp_flags)  
  2. {  
  3.     struct urb *urb;  
  4.     unsigned int npackets, i, j;  
  5.     u16 psize;  
  6.     u32 size;  
  7.     psize = le16_to_cpu(ep->desc.wMaxPacketSize);  
  8.     psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));  
  9.     size = stream->ctrl.dwMaxVideoFrameSize;  
  10.     npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags);   //分配urb缓冲区  
  11.     if (npackets == 0)  
  12.         return -ENOMEM;  
  13.     size = npackets * psize;  
  14.     for (i = 0; i < UVC_URBS; ++i) {  
  15.         urb = usb_alloc_urb(npackets, gfp_flags);   //分配urb  
  16.         if (urb == NULL) {  
  17.             uvc_uninit_video(stream, 1);  
  18.             return -ENOMEM;  
  19.         }  
  20.         urb->dev = stream->dev->udev;  //设置urb  
  21.         urb->context = stream;  
  22.         urb->pipe = usb_rcvisocpipe(stream->dev->udev,ep->desc.bEndpointAddress);  
  23.         urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;  
  24.         urb->interval = ep->desc.bInterval;  
  25.         urb->transfer_buffer = stream->urb_buffer[i];  
  26.         urb->transfer_dma = stream->urb_dma[i];  
  27.         urb->complete = uvc_video_complete;  
  28.         urb->number_of_packets = npackets;  
  29.         urb->transfer_buffer_length = size;  
  30.         for (j = 0; j < npackets; ++j) {  
  31.             urb->iso_frame_desc[j].offset = j * psize;  
  32.             urb->iso_frame_desc[j].length = psize;  
  33.         }  
  34.         stream->urb[i] = urb;  
  35.     }  
  36.     return 0;  
  37. }  
a.1.3.2 Bluk方式
[cpp]  view plain  copy
  1. static int uvc_init_video_bulk(struct uvc_streaming *stream,struct usb_host_endpoint *ep, gfp_t gfp_flags)  
  2. {  
  3.     struct urb *urb;  
  4.     unsigned int npackets, pipe, i;  
  5.     u16 psize;  
  6.     u32 size;  
  7.     psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff;  
  8.     size = stream->ctrl.dwMaxPayloadTransferSize;  
  9.     stream->bulk.max_payload_size = size;  
  10.     npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags);   //分配urb缓冲区  
  11.     if (npackets == 0)  
  12.         return -ENOMEM;  
  13.     size = npackets * psize;  
  14.     if (usb_endpoint_dir_in(&ep->desc))  
  15.         pipe = usb_rcvbulkpipe(stream->dev->udev,ep->desc.bEndpointAddress);  
  16.     else  
  17.         pipe = usb_sndbulkpipe(stream->dev->udev,ep->desc.bEndpointAddress);  
  18.   
  19.     if (stream->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)  
  20.         size = 0;  
  21.     for (i = 0; i < UVC_URBS; ++i) {  
  22.         urb = usb_alloc_urb(0, gfp_flags);  //分配urb  
  23.         if (urb == NULL) {  
  24.             uvc_uninit_video(stream, 1);  
  25.             return -ENOMEM;  
  26.         }  
  27.         usb_fill_bulk_urb(urb, stream->dev->udev, pipe,stream->urb_buffer[i], size, uvc_video_complete,stream);    //设置urb  
  28.         urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;  
  29.         urb->transfer_dma = stream->urb_dma[i];  
  30.         stream->urb[i] = urb;  
  31.     }  
  32.     return 0;  
  33. }  
a.1.3.1 同步方式和a.1.3.2 Bluk方式 两种方式初始化uvc视频主要是分配设置urb,然后在uvc_init_video函数中又通过usb_submit_urb提交了urb,两种方法的urb回调函数都是uvc_video_completea.2 urb回调函数uvc_video_complete
[cpp]  view plain  copy
  1. static void uvc_video_complete(struct urb *urb)  
  2. {  
  3.     struct uvc_streaming *stream = urb->context;  
  4.     struct uvc_video_queue *queue = &stream->queue;  
  5.     struct uvc_buffer *buf = NULL;  
  6.     unsigned long flags;  
  7.     int ret;  
  8.     switch (urb->status) {  
  9.     case 0:  
  10.         break;  
  11.     default:  
  12.         uvc_printk(KERN_WARNING, "Non-zero status (%d) in video completion handler.\n", urb->status);  
  13.     case -ENOENT:       /* usb_kill_urb() called. */  
  14.         if (stream->frozen)  
  15.             return;  
  16.     case -ECONNRESET:   /* usb_unlink_urb() called. */  
  17.     case -ESHUTDOWN:    /* The endpoint is being disabled. */  
  18.         uvc_queue_cancel(queue, urb->status == -ESHUTDOWN);  
  19.         return;  
  20.     }  
  21.     spin_lock_irqsave(&queue->irqlock, flags);  
  22.     if (!list_empty(&queue->irqqueue))  
  23.         buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,queue);  
  24.     spin_unlock_irqrestore(&queue->irqlock, flags);  
  25.     stream->decode(urb, stream, buf);    //调用uvc视频流的decode方法  
  26.     if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {   //再次提交urb  
  27.         uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",ret);  
  28.     }  
  29. }  

 

对于同步和bilk方式的decode方法分别是  
 stream->decode = uvc_video_decode_isoc;
 stream->decode = uvc_video_encode_bulk;  
这个在前面uvc_video_init函数中设置了
ok后面就开始解码了


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值