下面将给出Hi3559AV100外接UVC/MJPEG相机实时采图设计的整体流程,主要实现是通过V4L2接口将UVC/MJPEG相机采集的数据送入至MPP平台,经过VDEC、VPSS、VO最后通过HDMI的输出,首先给出(一)Linux USB摄像头驱动加载与分析。

板载平台:BOXER-8410AI

芯片型号:Hi3559AV100

相机型号:Logitch c270

开发环境:VM15.5+ubuntu16.04+Hilinux

之后可以参考后面两篇文章:

Hi3559AV100外接UVC/MJPEG相机实时采图设计(二):V4L2接口的实现(以YUV422为例):

https://www.cnblogs.com/iFrank/p/14403397.html

Hi3559AV100外接UVC/MJPEG相机实时采图设计(三):V4L2接口通过MPP平台输出:

https://www.cnblogs.com/iFrank/p/14403620.html

1、确定USB摄像头支持UVC

  首先,可以把USB摄像头插在PC端,然后通过设备管理器找到相机,右键选择属性,选择详细信息,更改属性一栏,选择硬件ID,从中可以看到USB摄像头的VID和PID,比如Logitech c270的ID号为:046d:0825,之后通过这个网页 http://www.ideasonboard.org/uvc/ 来查看是否支持 UVC,这个网站是 USB Video Class Linux device driver 的主页,里面有 UVC 的详细的介绍。根据前面的打印信息,根据自己的 ID 号, 这里是搜索 USB 摄像头的 VID 号:046d 和 PID 号:0825,主页如下所示:

  通过摄像头的 ID,可以看到该摄像头是否支持 UVC 和其他信息。绿勾代表支持。

2、配置与相机型号匹配的USB host驱动

  目前Hilinux系统自带了部分型号的usb摄像头驱动,但并不是支持所有市面上usb摄像头,像Logitch c270这一款usb摄像头就不支持,如果说linux kernel驱动中不支持,需要我们重新配置该驱动,或者需要进行裁剪等操作,而这个过程需要我们进行手动配置,配置过程如下:在内核目录下,输入如下命令(以emmc启动为例):

 1         待进入内核源代码目录后,执行以下操作
2
3 cp arch/arm64/configs/hi3559av100_arm64_big_little_emmc_defconfig .config
4
5
6 make ARCH=arm64 CROSS_COMPILE=aarch64-himix100-linux- menuconfig
7
8
9 cp .config arch/arm64/configs/hi3559av100_arm64_big_little_emmc_defconfig
10
11
12 osdrv顶层目录下执行:make BOOT_MEDIA=emmc AMP_TYPE=linux atf

执行 make ARCH=arm64 CROSS_COMPILE=aarch64-himix100-linux- menuconfig 后,弹出如下窗口:

之后进行驱动配置,打开UVC驱动等等。

  在配置好之后,弹出menuconfig窗口后,记得保存,保存完之后在手动修改usb驱动代码:修改位置如下:

linux-xxx\drivers\media\usb\uvc\uvc_driver.c

  设备插入时调用probe将会按默认的id_table来加载驱动,也就是这个uvc_ids末尾说的Generic USB Video Class,具体如下所示:

1     /* Generic USB Video Class */
2 { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) },
3 { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_15) },
4 {}

  在struct usb_device_id uvc_ids[]中模仿之前的加上自己的USB设备信息:

1     { .match_flags        = USB_DEVICE_ID_MATCH_DEVICE
2 | USB_DEVICE_ID_MATCH_INT_INFO,
3 .idVendor = 0x046d,
4 .idProduct = 0x0825,
5 .bInterfaceClass = USB_CLASS_VIDEO,
6 .bInterfaceSubClass = 1,
7 .bInterfaceProtocol = 0,
8 .driver_info = UVC_QUIRK_RESTORE_CTRLS_ON_INIT },

  注意一下这个driver_info的赋值,可以用来限制帧率,UVC_QUIRK_RESTORE_CTRLS_ON_INIT的值是0x400,这个设置好像是跟带宽有关系,没有深入了解,如果设的过小,将导致无法出图。而且USB2.0的带宽上限也只有480Mbit/s,连一个摄像头都够呛了。修改完之后,还需要重新编译内核。

  之后将摄像头插在板载上,终端出现如下:

  也可以通过命令ls /dev/video*查看video设备,如下所示, 到此驱动部分添加完成。

1 /dev/video0                                                     

3、UVC driver的研究

  上述终端显示的信息是由uvc_probe()函数输出,对应函数位置为linux-xxx\drivers\media\usb\uvc\uvc_driver.c,函数具体内容如下:

  1 static int uvc_probe(struct usb_interface *intf,
2 const struct usb_device_id *id)
3 {
4 struct usb_device *udev = interface_to_usbdev(intf);
5 struct uvc_device *dev;
6 int ret;
7
8 if (id->idVendor && id->idProduct)
9 uvc_trace(UVC_TRACE_PROBE, "Probing known UVC device %s "
10 "(%04x:%04x)\n", udev->devpath, id->idVendor,
11 id->idProduct);
12 else
13 uvc_trace(UVC_TRACE_PROBE, "Probing generic UVC device %s\n",
14 udev->devpath);
15
16 /* Allocate memory for the device and initialize it. */
17 if ((dev = kzalloc(sizeof *dev, GFP_KERNEL)) == NULL)
18 return -ENOMEM;
19
20 INIT_LIST_HEAD(&dev->entities);
21 INIT_LIST_HEAD(&dev->chains);
22 INIT_LIST_HEAD(&dev->streams);
23 atomic_set(&dev->nstreams, 0);
24 atomic_set(&dev->nmappings, 0);
25 mutex_init(&dev->lock);
26
27 dev->udev = usb_get_dev(udev);
28 dev->intf = usb_get_intf(intf);
29 dev->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
30 dev->quirks = (uvc_quirks_param == -1)
31 ? id->driver_info : uvc_quirks_param;
32
33 if (udev->product != NULL)
34 strlcpy(dev->name, udev->product, sizeof dev->name);
35 else
36 snprintf(dev->name, sizeof dev->name,
37 "UVC Camera (%04x:%04x)",
38 le16_to_cpu(udev->descriptor.idVendor),
39 le16_to_cpu(udev->descriptor.idProduct));
40
41 /* Parse the Video Class control descriptor. */
42 if (uvc_parse_control(dev) < 0) {
43 uvc_trace(UVC_TRACE_PROBE, "Unable to parse UVC "
44 "descriptors.\n");
45 goto error;
46 }
47
48 uvc_printk(KERN_INFO, "Found UVC %u.%02x device %s (%04x:%04x)\n",
49 dev->uvc_version >> 8, dev->uvc_version & 0xff,
50 udev->product ? udev->product : "<unnamed>",
51 le16_to_cpu(udev->descriptor.idVendor),
52 le16_to_cpu(udev->descriptor.idProduct));
53
54 if (dev->quirks != id->driver_info) {
55 uvc_printk(KERN_INFO, "Forcing device quirks to 0x%x by module "
56 "parameter for testing purpose.\n", dev->quirks);
57 uvc_printk(KERN_INFO, "Please report required quirks to the "
58 "linux-uvc-devel mailing list.\n");
59 }
60
61 /* Initialize the media device and register the V4L2 device. */
62 #ifdef CONFIG_MEDIA_CONTROLLER
63 dev->mdev.dev = &intf->dev;
64 strlcpy(dev->mdev.model, dev->name, sizeof(dev->mdev.model));
65 if (udev->serial)
66 strlcpy(dev->mdev.serial, udev->serial,
67 sizeof(dev->mdev.serial));
68 strcpy(dev->mdev.bus_info, udev->devpath);
69 dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
70 dev->mdev.driver_version = LINUX_VERSION_CODE;
71 media_device_init(&dev->mdev);
72
73 dev->vdev.mdev = &dev->mdev;
74 #endif
75 if (v4l2_device_register(&intf->dev, &dev->vdev) < 0)
76 goto error;
77
78 /* Initialize controls. */
79 if (uvc_ctrl_init_device(dev) < 0)
80 goto error;
81
82 /* Scan the device for video chains. */
83 if (uvc_scan_device(dev) < 0)
84 goto error;
85
86 /* Register video device nodes. */
87 if (uvc_register_chains(dev) < 0)
88 goto error;
89
90 #ifdef CONFIG_MEDIA_CONTROLLER
91 /* Register the media device node */
92 if (media_device_register(&dev->mdev) < 0)
93 goto error;
94 #endif
95 /* Save our data pointer in the interface data. */
96 usb_set_intfdata(intf, dev);
97
98 /* Initialize the interrupt URB. */
99 if ((ret = uvc_status_init(dev)) < 0) {
100 uvc_printk(KERN_INFO, "Unable to initialize the status "
101 "endpoint (%d), status interrupt will not be "
102 "supported.\n", ret);
103 }
104
105 uvc_trace(UVC_TRACE_PROBE, "UVC device initialized.\n");
106 usb_enable_autosuspend(udev);
107 return 0;
108
109 error:
110 uvc_unregister_video(dev);
111 return -ENODEV;
112 }
  对于初始kernel内核USB驱动应该是加载了一部分支持 UVC 摄像头的驱动,在默认的uvc_driver 下,是没有我们摄像头 046d 0825 ID 号的,需要我们手动添加。当内核发现与 uvc_ids 匹配的 USB 摄像头就会调用 uvc_probe 函数,一旦内核发现插入的 USB 摄像头被匹配后,最终就会调用 uvc_probe 函数。
  USB摄像头驱动其实就是一个字符设备驱动,重点关注v4l2_fops结构体,如下所示:
 1 static const struct file_operations v4l2_fops = {
2 .owner = THIS_MODULE,
3 .read = v4l2_read,
4 .write = v4l2_write,
5 .open = v4l2_open,
6 .get_unmapped_area = v4l2_get_unmapped_area,
7 .mmap = v4l2_mmap,
8 .unlocked_ioctl = v4l2_ioctl,
9 #ifdef CONFIG_COMPAT
10 .compat_ioctl = v4l2_compat_ioctl32,
11 #endif
12 .release = v4l2_release,
13 .poll = v4l2_poll,
14 .llseek = no_llseek,
15 };
  而USB摄像头结合V4L2接口时,当应用程序调用 open 函数,例如: open("/dev/video0",....),首先就会调用到 v4l2 核心里的 open 函数,也就是 v4l2_open 函数(v4l2-dev.c)。而在v4l2-open 函数中调用了 vdev->fops->open(filp),相当于调用 uvc_v4l2_open()函数。这个函数的实现在\drivers\media\usb\uvc\uvc_v4l2.c 里。同样地,vdev->fops->unlocked_ioctl(filp,cmd,arg)(v4l2-dev.c);最后相当于调用 uvc_v4l2_ioctl()函数,它又调用 video_usercopy(file,cmd,arg,uvc_v4l2_do_ioctl);函数,video_usercopy()函数的作用从名字上可以猜测,它是根据用户空间传递过来的 cmd 命令,调用 uvc_v4l2_do_ioctl()函数来解析 arg 参数。

  ctrl 属性的函数调用流程
  uvc_probe
    uvc_register_chains
      uvc_register_terms
        uvc_register_video
          video_register_device__video_register_device
            determine_valid_ioctls
  这些 ctrl 属性就是 USB 摄像头的各种属性,比如亮度的调节,打开、关闭STREAM 等等操作,这些是 v4l2 核心最最复杂的工作了,没有之一。
参考: \drivers\media\v4l2-core\v4l2-dev.c

Hi3559AV100外接UVC/MJPEG相机实时采图设计(一):Linux USB摄像头驱动分析的更多相关文章

  1. Hi3559AV100外接UVC/MJPEG相机实时采图设计(四):VDEC_Send_Stream线程分析

    下面随笔将对Hi3559AV100外接UVC/MJPEG相机实现实时采图设计的关键点-VDEC_Send_Stream线程进行分析,一两个星期前我写了有三篇系列随笔,已经实现了项目功能,大家可以参考下 ...

  2. Hi3559AV100外接UVC/MJPEG相机实时采图设计(三):V4L2接口通过MPP平台输出

    可以首先参考前面两篇文章: Hi3559AV100外接UVC/MJPEG相机实时采图设计(一):Linux USB摄像头驱动分析: https://www.cnblogs.com/iFrank/p/1 ...

  3. Hi3559AV100外接UVC/MJPEG相机实时采图设计(二):V4L2接口的实现(以YUV422为例)

    下面将给出Hi3559AV100外接UVC/MJPEG相机实时采图设计的整体流程,主要实现是通过V4L2接口将UVC/MJPEG相机采集的数据送入至MPP平台,经过VDEC.VPSS.VO最后通过HD ...

  4. Dalsa 8K彩色相机Camera link C#采图

    一个采图工具,所以界面做的很简单. private SapAcquisition m_Acquisition; private SapBuffer m_Buffers; private SapAcqT ...

  5. 相机拍的图,电脑上画的图,word里的文字,电脑屏幕,手机屏幕,相机屏幕显示大小一切的一切都搞明白了!

    相机拍的图,电脑上画的图,word里的文字,电脑屏幕,手机屏幕,相机屏幕显示大小一切的一切都搞明白了! 先说图片X×dpi=点数dotX是图片实际尺寸,简单点,我们只算图片的高吧,比如说拍了张图片14 ...

  6. FusionCharts制作实时刷新图

    转自:http://yklovejava-163-com.iteye.com/blog/1889949 下面介绍的是用FusionCharts制作实时刷新图的过程(FusionCharts确实太好用了 ...

  7. Android相机实时自动对焦的完美实现

    https://zhidao.baidu.com/question/873328177698804372.html Android相机实时自动对焦的完美实现 http://blog.csdn.net/ ...

  8. 关于nagios系统下使用shell脚本自定义监控插件的编写以及没有实时监控图的问题

    关于nagios系统下shell自定义监控插件的编写.脚本规范以及没有实时监控图的问题的解决办法 在自已编写监控插件之前我们首先需要对nagios监控原理有一定的了解 Nagios的功能是监控服务和主 ...

  9. RTSP流和USB摄像头转MJPEG使用VLC

    测试环境: 系统: Ubuntu14.04 LTS Desktop 设备:海康IP摄像头和USB摄像头 1.需要先安装vlc包,命令行运行 sudo apt-get update sudo apt-g ...

随机推荐

  1. Codeforces Round #650 (Div. 3) C. Social Distance

    题目链接:https://codeforces.com/contest/1367/problem/C 题意 给出一个长为 $n$ 的 $01$字符串,两个相邻 $1$ 间距应大于 $k$,初始序列合法 ...

  2. hdu5491 The Next

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission ...

  3. Codeforces Round #307 (Div. 2) B. ZgukistringZ

    Professor GukiZ doesn't accept string as they are. He likes to swap some letters in string to obtain ...

  4. 表达式目录树插件xLiAd.SqlEx.Core

    表达式目录树使用时 引用xLiAd.SqlEx.Core ,是一个很好的插件 using xLiAd.SqlEx.Core.Helper; Expression<Func<Reported ...

  5. linux环境下使用jmeter进行分布式测试

    1.前言 熟练使用jmeter进行性能测试的工程师都知道,jmeter的客户端性能是有点差的.这会导致一个问题,其客户端的性能损耗会干扰到性能测试的结果,而且当线程数/并发大到一定程度时,客户端性能会 ...

  6. 支撑性服务 & 自动化

    连载传送门: 什么是云原生? 云原生设计理念 .NET 微服务 谈到云原生,绕不开"容器化" Backing services 云原生系统依赖于许多不同的辅助资源,例如数据存储.消 ...

  7. Linux 日志切割方法总结--Logrotate

    一.Logrotate 使用方法 对于Linux系统安全来说,日志文件是极其重要的工具.logrotate程序是一个日志文件管理工具.用于分割日志文件,删除旧的日志文件,并创建新的日志文件,起到&qu ...

  8. .NET Core项目自动化测试和代码覆盖率审查

    这篇文章给大家分享一下,如何配置.NET Core项目自动化测试和代码覆盖率审查. 基本知识,请参考这里: https://docs.microsoft.com/en-us/dotnet/core/t ...

  9. CodeForces - 803C Maximal GCD 【构造】

    You are given positive integer number n. You should create such strictly increasing sequence of k po ...

  10. js array flat all in one

    js array flat all in one array flat flatMap flatMap > flat + map https://developer.mozilla.org/en ...