转载于: 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. uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n");
  7. stream = video_drvdata(file);   //获取uvc视频流
  8. if (stream->dev->state & UVC_DEV_DISCONNECTED)    //设备没连接
  9. return -ENODEV;
  10. ret = usb_autopm_get_interface(stream->dev->intf);    //唤醒设备
  11. if (ret < 0)
  12. return ret;
  13. /* Create the device handle. */
  14. handle = kzalloc(sizeof *handle, GFP_KERNEL);   //创建uvc句柄
  15. if (handle == NULL) {
  16. usb_autopm_put_interface(stream->dev->intf);
  17. return -ENOMEM;
  18. }
  19. if (atomic_inc_return(&stream->dev->users) == 1) {
  20. ret = uvc_status_start(stream->dev); //uvc状态开始
  21. if (ret < 0) {
  22. usb_autopm_put_interface(stream->dev->intf);
  23. atomic_dec(&stream->dev->users);
  24. kfree(handle);
  25. return ret;
  26. }
  27. }
  28. handle->chain = stream->chain;    //捆绑uvc句柄和uvc视频链
  29. handle->stream = stream; //捆绑uvc句柄和uvc视频流
  30. handle->state = UVC_HANDLE_PASSIVE;  //设置uvc状态为未激活
  31. file->private_data = handle; //将uvc句柄作为文件的私有数据
  32. return 0;
  33. }
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
http://linuxtv.org/downloads/v4l-dvb-apis/
常用的命令
[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. switch (cmd) {
  9. ...
  10. case ...:
  11. {
  12. ...
  13. break;
  14. }
  15. return ret;
  16. }
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. return 0;
  72. }

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. if (stream->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
  19. size = 0;
  20. for (i = 0; i < UVC_URBS; ++i) {
  21. urb = usb_alloc_urb(0, gfp_flags);  //分配urb
  22. if (urb == NULL) {
  23. uvc_uninit_video(stream, 1);
  24. return -ENOMEM;
  25. }
  26. usb_fill_bulk_urb(urb, stream->dev->udev, pipe,stream->urb_buffer[i], size, uvc_video_complete,stream);    //设置urb
  27. urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
  28. urb->transfer_dma = stream->urb_dma[i];
  29. stream->urb[i] = urb;
  30. }
  31. return 0;
  32. }

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后面就开始解码了

转载于:https://www.cnblogs.com/tureno/articles/6888847.html

uvc摄像头代码解析7相关推荐

  1. uvc摄像头代码解析之描述符

    1.uvc驱动模块入口 module_init(uvc_init); //1.模块入口 2.初始化函数 static int __init uvc_init(void) // 2.初始化函数 {int ...

  2. uvc摄像头代码解析2

    1.uvc驱动模块入口 module_init(uvc_init); //1.模块入口 2.初始化函数 static int __init uvc_init(void) // 2.初始化函数 {int ...

  3. uvc摄像头代码解析1

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

  4. uvc摄像头代码解析4

    7.u vc _parse_format 7.1 uvc格式描述符 [cpp]   struct uvc_format_desc { //uvc格式描述符   char *name; //uvc格式描 ...

  5. uvc摄像头代码解析5

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

  6. uvc摄像头代码解析6

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

  7. UVC摄像头视频流原理解析

    1.UVC摄像i头从插入到加载驱动,看我前面的文章分析过程 2.UVC摄像头驱动加载时在kernel\drivers\media\usb\uvc\uvc_driver.c uvc_probe-> ...

  8. Android UVC摄像头方向调试

    Platform: RK3368 OS: Android 6.0 Kernel: 3.10.0 UVC摄像头方向调试 方法1修改CameraHal 修改代码位置hardware/rockchip/ca ...

  9. rk3288 调试dvp摄像头_RK3288 uvc摄像头调试

    [           移植Linux3.4.2版本内核到mini2440(二)--添加网卡.UVC摄像头.LCD驱动     ] 曾经在全志平台上调试过UVC摄像头,当时调试过程比较流畅,丝毫没有碰 ...

最新文章

  1. 清华学长请授接口自动化测试进阶攻略
  2. ArcGIS 10 许可配置
  3. python控制电机_树莓派Python控制步进电机
  4. 划分字母区间(双指针,贪心)
  5. [codevs 1035] 火车停留
  6. Redis集群添加节点
  7. 给你一碗孟婆汤,你会忘记什么?
  8. DOC命令大全--(转)
  9. 华夏基金:养老是基金业下一个20年最大风口
  10. 价值连城 生成对抗网络(Gans) 的作者Ian Goodfellow的采访 给深度学习从业者的建议
  11. python面板数据分析代码_【译】用python做计量之面板数据模型
  12. attention 文字识别算法_一文带你了解文字识别
  13. Python 微信公众号文章爬取 简单记录一下
  14. App提交审核被拒的原因汇总
  15. 超高频RFID电子标签技术和应用分析
  16. HTML文档繁转简,excel简繁转换 切换到“审阅”,点击“繁转简”:
  17. Less系列之混合(Mixins)
  18. 计算机组成原理笔记|03存储系统
  19. python实现俄罗斯方块小游戏
  20. 动作捕捉技术在四足仿生机器人研究中的应用

热门文章

  1. 【linux草鞋应用编程系列】_4_ 应用程序多线程
  2. shell学习之shell执行方式及排错
  3. 转:QQ圈子:社交神器还是隐私魔鬼?
  4. CakePHP中文手册【翻译】-请求处理组件
  5. oracle学习 sql基本语法(三),Oracle数据库学习三
  6. 二相并行FIR滤波器的matlab及使用FIR IP 核的FPGA实现
  7. C++实现Hash表
  8. 双向口和准双向口操作的不同!
  9. github使用教程及小问题
  10. kivy 的on_touch_move和on_touch_down