1. 摄像头

本文主要介绍如何采集摄像头数据。

1.1. v4l2-utils介绍

V4L2-Utils是一个Linux下的视频设备管理和调试工具集,主要用于配置和控制Linux内核中的V4L2(Video for Linux version 2)视频设备。

1.1.1. 基本概念

  • V4L2:Video for Linux version 2,是Linux内核中用于视频设备驱动程序的标准接口。它提供了一套丰富的API,允许应用程序访问和控制视频设备。

  • V4L2-Utils:基于V4L2 API开发的一套命令行工具集,包含了多个用于查询、设置和调试视频设备的工具。

1.1.2. 主要功能

  • 列出视频设备:可以列出系统中所有支持V4L2的视频设备,包括设备名称、设备节点等信息。

  • 查询设备参数:可以查询视频设备的各种参数,如分辨率、帧率、像素格式、亮度、对比度等。

  • 设置设备参数:可以根据需要设置视频设备的参数,以满足不同的应用场景需求。

  • 视频捕获:支持通过内存映射(mmap)或用户指针(read)方式捕获视频流,并将其保存为文件或进行其他处理。

  • 设备测试与调试:提供了多种测试和调试功能,如测试图案生成、设备兼容性测试等,有助于用户快速定位和解决视频设备相关的问题。

1.1.3. 常用工具

  • v4l2-ctl:主要用于控制和查询视频设备的参数。它提供了丰富的命令选项,如列出设备、查询和设置控制值、捕获视频流等。

  • media-ctl:主要用于查看和配置Media Framework中的实体(Entity)信息,如格式、裁剪、链接使能等。

1.2. 使用v4l2-ctl采集USB摄像头数据

开发板上电,插入USB摄像头,系统检测到USB摄像头插入后,会有如下打印信息:

../../_images/show-board-uvc_camera.png

查看USB摄像头的视频捕获节点:

1
v4l2-ctl --list-devices
../../_images/show-operation-uvc_camera-devnode.png
  • /dev/video* : 视频捕获设备节点(这里只有/dev/video10具有视频捕获功能)

  • /dev/media* : media子系统设备节点

对于USB摄像头而言,只需要关注/dev/video*节点。

查看摄像头支持的格式:

1
v4l2-ctl -d /dev/video10 --list-formats-ext
../../_images/show-operation-uvc_camera-enumfmt.png

设置/dev/video10设备节点的视频格式为MJPG,分辨率为640*480,帧率30fps:

1
2
v4l2-ctl -d /dev/video10 --set-fmt-video=width=640,height=480,pixelformat=MJPG
v4l2-ctl -d /dev/video10 --set-parm=30

捕获一帧视频图像,并保存到当前目录:

1
v4l2-ctl --verbose -d /dev/video10 --stream-mmap=4 --stream-skip=3 --stream-count=5 --stream-to=./01.jpg --stream-poll
../../_images/show-operation-uvc_camera-cappic.png

查看刚刚捕获的图像:

../../_images/show-operation-uvc_camera-01.png

1.3. 使用v4l2-ctl、media-ctl采集MIPI摄像头数据

MIPI Sensor通路往往会涉及传感器Sensor、CSI接口、ISP等多个模块,每个模块都有其相应的驱动程序, 内核驱动会将这些模块注册为一个个/dev/v4l-subdev*节点,以供用户态使用,但这不是必须的,如ISP驱动不一定会提供相应的设备节点供用户态使用。 MIPI摄像头的驱动程序会比USB摄像头驱动程序复杂的多,于是需要引入media子系统来管理各个模块之间的连接,如/dev/media*节点可以用来查看模块之间的拓扑结构。

这里以猫1和MIPI接口的OV8858摄像头为例,执行如下命令开启OV8858设备树插件:

../../_images/show-board-mipi_camera-dtbo.png

查看MIPI通路中的相关节点:

1
v4l2-ctl --list-devices
../../_images/show-operation-mipi_camera-devnode.png

执行如下命令查看拓扑结构:

1
media-ctl -p -d /dev/media0
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
Media controller API version 5.10.198

Media device information
------------------------
driver          rkisp-vir0
model           rkisp0
serial
bus info
hw revision     0x0
driver version  5.10.198

Device topology
- entity 1: rkisp-isp-subdev (4 pads, 8 links)
            type V4L2 subdev subtype Unknown flags 0
            device node name /dev/v4l-subdev0
      pad0: Sink
               [fmt:SBGGR10_1X10/3264x2448 field:none
               crop.bounds:(0,0)/3264x2448
               crop:(0,0)/3264x2448]
               <- "rkisp-csi-subdev":1 [ENABLED]
               <- "rkisp_rawrd0_m":0 []
               <- "rkisp_rawrd2_s":0 []
      pad1: Sink
               <- "rkisp-input-params":0 [ENABLED]
      pad2: Source
               [fmt:YUYV8_2X8/3264x2448 field:none colorspace:smpte170m quantization:full-range
               crop.bounds:(0,0)/3264x2448
               crop:(0,0)/3264x2448]
               -> "rkisp_mainpath":0 [ENABLED]
               -> "rkisp_selfpath":0 [ENABLED]
               -> "rkisp_iqtool":0 [ENABLED]
      pad3: Source
               -> "rkisp-statistics":0 [ENABLED]

- entity 6: rkisp-csi-subdev (6 pads, 5 links)
            type V4L2 subdev subtype Unknown flags 0
            device node name /dev/v4l-subdev1
      pad0: Sink
               [fmt:SBGGR10_1X10/3264x2448 field:none]
               <- "rockchip-csi2-dphy1":1 [ENABLED]
      pad1: Source
               [fmt:SBGGR10_1X10/3264x2448 field:none]
               -> "rkisp-isp-subdev":0 [ENABLED]
      pad2: Source
               -> "rkisp_rawwr0":0 [ENABLED]
      pad3: Source
      pad4: Source
               -> "rkisp_rawwr2":0 [ENABLED]
      pad5: Source
               -> "rkisp_rawwr3":0 [ENABLED]

- entity 13: rkisp_mainpath (1 pad, 1 link)
            type Node subtype V4L flags 0
            device node name /dev/video0
      pad0: Sink
               <- "rkisp-isp-subdev":2 [ENABLED]

- entity 19: rkisp_selfpath (1 pad, 1 link)
            type Node subtype V4L flags 0
            device node name /dev/video1
      pad0: Sink
               <- "rkisp-isp-subdev":2 [ENABLED]

- entity 25: rkisp_rawwr0 (1 pad, 1 link)
            type Node subtype V4L flags 0
            device node name /dev/video2
      pad0: Sink
               <- "rkisp-csi-subdev":2 [ENABLED]

- entity 31: rkisp_rawwr2 (1 pad, 1 link)
            type Node subtype V4L flags 0
            device node name /dev/video3
      pad0: Sink
               <- "rkisp-csi-subdev":4 [ENABLED]

- entity 37: rkisp_rawwr3 (1 pad, 1 link)
            type Node subtype V4L flags 0
            device node name /dev/video4
      pad0: Sink
               <- "rkisp-csi-subdev":5 [ENABLED]

- entity 43: rkisp_iqtool (1 pad, 1 link)
            type Node subtype V4L flags 0
            device node name /dev/video5
      pad0: Sink
               <- "rkisp-isp-subdev":2 [ENABLED]

- entity 49: rkisp_rawrd0_m (1 pad, 1 link)
            type Node subtype V4L flags 0
            device node name /dev/video6
      pad0: Source
               -> "rkisp-isp-subdev":0 []

- entity 55: rkisp_rawrd2_s (1 pad, 1 link)
            type Node subtype V4L flags 0
            device node name /dev/video7
      pad0: Source
               -> "rkisp-isp-subdev":0 []

- entity 61: rkisp-statistics (1 pad, 1 link)
            type Node subtype V4L flags 0
            device node name /dev/video8
      pad0: Sink
               <- "rkisp-isp-subdev":3 [ENABLED]

- entity 67: rkisp-input-params (1 pad, 1 link)
            type Node subtype V4L flags 0
            device node name /dev/video9
      pad0: Source
               -> "rkisp-isp-subdev":1 [ENABLED]

- entity 73: rockchip-csi2-dphy1 (2 pads, 2 links)
            type V4L2 subdev subtype Unknown flags 0
            device node name /dev/v4l-subdev2
      pad0: Sink
               [fmt:SBGGR10_1X10/3264x2448@10000/230000 field:none]
               <- "m00_b_ov8858 1-0036":0 [ENABLED]
      pad1: Source
               -> "rkisp-csi-subdev":0 [ENABLED]

- entity 76: m00_b_ov8858 1-0036 (1 pad, 1 link)
            type V4L2 subdev subtype Sensor flags 0
            device node name /dev/v4l-subdev3
      pad0: Source
               [fmt:SBGGR10_1X10/3264x2448@10000/230000 field:none]
               -> "rockchip-csi2-dphy1":0

执行如下命令确认视频捕获设备:

1
2
media-ctl -d /dev/media0 -e "rkisp_selfpath"
media-ctl -d /dev/media0 -e "rkisp_mainpath"
../../_images/show-operation-mipi_camera-devnode2.png

查看摄像头支持的格式:

1
v4l2-ctl -d /dev/video0 --list-formats-ext
../../_images/show-operation-mipi_camera-enumfmt.png

采集一帧视频图像,并保存到当前目录:

1
v4l2-ctl --verbose -d /dev/video0 --set-fmt-video=width=640,height=480,pixelformat=NV21 --stream-mmap=4 --stream-skip=3 --stream-count=1 --stream-to=./video0.yuv --stream-poll
../../_images/show-operation-mipi_camera-cappic.png

windows下使用yuv播放软件查看图像:

../../_images/show-operation-mipi_camera-video0.png

1.4. UVC摄像头应用程序编写

本例将使用支持MJPEG格式输出的USB摄像头,程序中,会采集摄像头数据并保存为一张张 的.jpg格式的图片。

1.4.1. 获取程序

程序位于lubancat_rk_code_storage/expansion_board/camera/uvc_to_jpg.c, 将uvc_to_jpg.c文件夹拷贝到板卡。

1.4.2. 代码测试

将USB摄像头插到板卡上,执行如下命令编译运行程序:

1
2
3
4
5
# 编译程序
sudo gcc -o uvc_to_jpg uvc_to_jpg.c

# 运行程序
sudo ./uvc_to_jpg /dev/video10
../../_images/show-operation-coderun-uvc.png
../../_images/show-operation-coderun-uvc-02.png

1.5. MIPI摄像头应用程序编写

本应用程序和上一个应用程序的操作流程是一致的,主要区别在于单平面视频采集和多平面视频采集。 本例将使用支持NV21格式输出的MIPI OV8588摄像头,程序中,会采集摄像头数据并保存为一帧帧的.yuv格式的视频帧文件。

1.5.1. 获取程序

程序位于lubancat_rk_code_storage/expansion_board/camera/uvc_to_yuv.c, 将uvc_to_yuv.c文件夹拷贝到板卡。

1.5.2. 代码测试

将MIPI摄像头连接到板卡上的MIPI CSI接口,执行如下命令编译运行程序:

1
2
3
4
5
# 编译程序
sudo gcc -o mipi_to_yuv mipi_to_yuv.c

# 运行程序
sudo ./mipi_to_yuv /dev/video0
../../_images/show-operation-coderun-mipi.png
../../_images/show-operation-coderun-mipi-02.png