RV1106上Alpine系统使用摄像头

前言说明

  1. 我测试的硬件设备是:SoloLinker-A V1版本 RV1106G3 256M内存 8G储存EMMCSoloLinker-A V2版本 RV1106G2 128M内存 128储存NAND

  2. 运行系统用的是:RV1106-SOLOLINKER-EMMC_WIFI_ALPINE-240407

  3. 测试的屏幕及摄像头:大显伟业4.0寸RGB屏单目摄像头:GC2093

  4. 如果系统没装软件可:apk add v4l-utils ffmpeg ffplay (ffmpeg需要空间稍大,NAND的128M注意是否够)

准备工作

  1. 列出所有V4L2设备,找到所需设备
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
Alpine:~# v4l2-ctl --list-devices
rkisp-statistics (platform: rkisp):
/dev/video19
/dev/video20

rkcif-mipi-lvds (platform:rkcif):
/dev/media0

rkcif (platform:rkcif-mipi-lvds):
/dev/video0
/dev/video1
/dev/video2
/dev/video3
/dev/video4
/dev/video5
/dev/video6
/dev/video7
/dev/video8
/dev/video9
/dev/video10

rkisp_mainpath (platform:rkisp-vir0):
/dev/video11
/dev/video12
/dev/video13
/dev/video14
/dev/video15
/dev/video16
/dev/video17
/dev/video18
/dev/media1

Alpine:~#

# 我目前使用的是单目摄像头,可以看到 rkisp-vir0 下 /dev/media1 对应 /dev/video11
# 如果你使用的是双目摄像头,应该会有 rkisp-vir2 下 /dev/media2 之类的
# 双目摄像头可能还需要修改DTS:https://wiki.t-firefly.com/Core-3566JD4/driver_camera.html
  1. 确认media1所属video*节点
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
# 根据如下输出可知它所属节点是:/dev/video11 

Alpine:~# media-ctl -p -d /dev/media1 -e rkisp_mainpath
Media controller API version 5.10.160

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

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

Alpine:~#


# 下面命令分别显示RKISP的MP及SP节点的设备路径,它们都能输出图像
Alpine:~# media-ctl -d /dev/media1 -e "rkisp_mainpath"
/dev/video11
Alpine:~# media-ctl -d /dev/media1 -e "rkisp_selfpath"
/dev/video12
Alpine:~#
  1. 列出该摄像头支持的格式
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
# 根据如下可知RKISP的MP节点支持:UYVY NV16 NV61 NV21 NV12 NM21 NM12
# 而RKISP的SP节点比其多支持几个:UYVY NV16 NV61 NV21 NV12 NM21 NM12 GREY XR24 RGBP

Alpine:~# v4l2-ctl --list-formats-ext -d /dev/video11
ioctl: VIDIOC_ENUM_FMT
Type: Video Capture Multiplanar

[0]: 'UYVY' (UYVY 4:2:2)
Size: Stepwise 32x32 - 1920x1080 with step 8/8
[1]: 'NV16' (Y/CbCr 4:2:2)
Size: Stepwise 32x32 - 1920x1080 with step 8/8
[2]: 'NV61' (Y/CrCb 4:2:2)
Size: Stepwise 32x32 - 1920x1080 with step 8/8
[3]: 'NV21' (Y/CrCb 4:2:0)
Size: Stepwise 32x32 - 1920x1080 with step 8/8
[4]: 'NV12' (Y/CbCr 4:2:0)
Size: Stepwise 32x32 - 1920x1080 with step 8/8
[5]: 'NM21' (Y/CrCb 4:2:0 (N-C))
Size: Stepwise 32x32 - 1920x1080 with step 8/8
[6]: 'NM12' (Y/CbCr 4:2:0 (N-C))
Size: Stepwise 32x32 - 1920x1080 with step 8/8

Alpine:~# v4l2-ctl --list-formats-ext -d /dev/video12
ioctl: VIDIOC_ENUM_FMT
Type: Video Capture Multiplanar

[0]: 'UYVY' (UYVY 4:2:2)
Size: Stepwise 32x32 - 1920x1080 with step 8/8
[1]: 'NV16' (Y/CbCr 4:2:2)
Size: Stepwise 32x32 - 1920x1080 with step 8/8
[2]: 'NV61' (Y/CrCb 4:2:2)
Size: Stepwise 32x32 - 1920x1080 with step 8/8
[3]: 'NV21' (Y/CrCb 4:2:0)
Size: Stepwise 32x32 - 1920x1080 with step 8/8
[4]: 'NV12' (Y/CbCr 4:2:0)
Size: Stepwise 32x32 - 1920x1080 with step 8/8
[5]: 'NM21' (Y/CrCb 4:2:0 (N-C))
Size: Stepwise 32x32 - 1920x1080 with step 8/8
[6]: 'NM12' (Y/CbCr 4:2:0 (N-C))
Size: Stepwise 32x32 - 1920x1080 with step 8/8
[7]: 'GREY' (8-bit Greyscale)
Size: Stepwise 32x32 - 1920x1080 with step 8/8
[8]: 'XR24' (32-bit BGRX 8-8-8-8)
Size: Stepwise 32x32 - 1920x1080 with step 8/8
[9]: 'RGBP' (16-bit RGB 5-6-5)
Size: Stepwise 32x32 - 1920x1080 with step 8/8
Alpine:~#
  1. 也可直接获取指定设备的所有信息
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
Alpine:~# v4l2-ctl --all --device /dev/video11
Driver Info:
Driver name : rkisp_v7
Card type : rkisp_mainpath
Bus info : platform:rkisp-vir0
Driver version : 2.2.2
Capabilities : 0x84201000
Video Capture Multiplanar
Streaming
Extended Pix Format
Device Capabilities
Device Caps : 0x04201000
Video Capture Multiplanar
Streaming
Extended Pix Format
Priority: 2
Format Video Capture Multiplanar:
Width/Height : 1920/1080
Pixel Format : 'NV12' (Y/CbCr 4:2:0)
Field : None
Number of planes : 1
Flags :
Colorspace : Default
Transfer Function : Default
YCbCr/HSV Encoding: Default
Quantization : Full Range
Plane 0 :
Bytes per Line : 1920
Size Image : 3110400
Selection Video Capture: crop, Left 0, Top 0, Width 1920, Height 1080, Flags:
Selection Video Capture: crop_bounds, Left 0, Top 0, Width 1920, Height 1080, Flags:
Selection Video Output: crop, Left 0, Top 0, Width 1920, Height 1080, Flags:
Selection Video Output: crop_bounds, Left 0, Top 0, Width 1920, Height 1080, Flags:

Image Processing Controls

pixel_rate 0x009f0902 (int64) : min=0 max=1000000000 step=1 default=1000000000 value=237600000 flags=read-only, volatile
Alpine:~#

可调参数

  1. 查看支持的参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 查看驱动支持的设置参数和取值范围以及当前值
Alpine:~# v4l2-ctl -d /dev/v4l-subdev2 -L

User Controls

exposure 0x00980911 (int) : min=1 max=1121 step=1 default=1120 value=400
horizontal_flip 0x00980914 (bool) : default=0 value=1
vertical_flip 0x00980915 (bool) : default=0 value=1

Image Source Controls

vertical_blanking 0x009e0901 (int) : min=45 max=15303 step=1 default=45 value=45
horizontal_blanking 0x009e0902 (int) : min=280 max=280 step=1 default=280 value=280 flags=read-only
analogue_gain 0x009e0903 (int) : min=64 max=8192 step=1 default=64 value=64

Image Processing Controls

link_frequency 0x009f0901 (intmenu): min=0 max=1 default=0 value=0 (297000000 0x11b3dc40)
0: 297000000 (0x11b3dc40)
1: 396000000 (0x179a7b00)
pixel_rate 0x009f0902 (int64) : min=0 max=316800000 step=1 default=237600000 value=237600000 flags=read-only
Alpine:~#
  1. 从上可知可以调节的参数为
参数 说明
exposure 曝光时间,单位是微秒。通过适当调节曝光时间可以改变图像的亮度
horizontal_flip 水平翻转开关,0 表示关闭,1 表示开启
vertical_flip 垂直翻转开关,0 表示关闭,1 表示开启
vertical_blanking 垂直消隐时间,单位为行数
horizontal_blanking 水平消隐时间,单位为像素数
analogue_gain 模拟增益控制,可以通过调节该参数来改变图像的亮度
link_frequency 接口频率,影响传输速率,根据不同的频率可以选择不同的传输速率
pixel_rate 像素速率,用于表示相机输出图像的数据传输速率
  1. 调节参数(重启恢复默认)
1
2
3
4
5
6
7
8
9
10
11
12
#关闭帧压缩
echo 0 > /sys/devices/platform/rkcif-mipi-lvds/compact_test

# 增加曝光度
v4l2-ctl -d /dev/v4l-subdev2 --set-ctrl=exposure=1120

# 显示的图像旋转90度
v4l2-ctl -d /dev/v4l-subdev2 --set-ctrl=horizontal_flip=1
v4l2-ctl -d /dev/v4l-subdev2 --set-ctrl=vertical_flip=1

# 设置显示图像的亮度
v4l2-ctl -d /dev/v4l-subdev2 --set-ctrl 'exposure=1120,analogue_gain=500'

操作摄像头

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 帧率测试
v4l2-ctl -d /dev/video11 --set-fmt-video=width=1920,height=1080,pixelformat='NV12' --stream-mmap=3 --stream-poll

# 抓取video0的GB10帧
v4l2-ctl -d /dev/video0 --set-fmt-video=width=1920,height=1080,pixelformat='GB10' --stream-mmap=4 --stream-skip=3 --stream-to=/tmp/GB10.raw --stream-count=1 --stream-poll

# 抓取video11的NV12帧
v4l2-ctl -d /dev/video11 --set-fmt-video=width=1920,height=1080,pixelformat='NV12' --stream-mmap=4 --stream-skip=3 --stream-to=/tmp/NV12.yuv --stream-count=1 --stream-poll

# PC上播放抓取的帧
ffplay -f rawvideo -video_size 1920x1080 -pixel_format nv12 /tmp/NV12.yuv

# 将yuv图像转为jpg文件,这样就可以在PC上正常查看了
ffmpeg -pix_fmt nv12 -s 1920x1080 -i /tmp/NV12.yuv /tmp/result.jpg


# 视频录制
v4l2-ctl -d /dev/video11 --set-fmt-video=width=480,height=480,pixelformat='NV12' --stream-mmap --stream-to=/root/video.yuv --stream-count=60

# 转换格式为mp4
ffmpeg -f rawvideo -pixel_format nv12 -video_size 480x480 -framerate 30 -i video.yuv -c:v libx264 output.mp4

# 在LCD中播放
ffmpeg -pix_fmt bgra -vf scale=480:480 -f fbdev /dev/fb0 -i output.mp4

常用命令参数

  1. V4L2命令参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
v4l2-ctl -d /dev/video11 --set-fmt-video=width=1920,height=1080,pixelformat='NV12' \
--stream-mmap=4 --stream-skip=3 --stream-to=/tmp/NV12.yuv --stream-count=1 --stream-poll

-d # 摄像头对应设备文件
--set-fmt-video # 根据上面查询到的信息指定摄像头图像格式,这里我们选择NV12格式,分辨率为1920x1080
--stream-mmap # 使用mmap方式获取摄像头图像数据,也就是说,摄像头图像数据会被映射到用户空间,用户空间可以直接访问摄像头图像数据。
--stream-to # 指定帧数据保存的文件路径
--stream-skip # 指定丢弃(不保存到文件)前几帧
--stream-count # 指定抓取的帧数,不包括--stream-skip丢弃的数量
--stream-poll # 采用异步IO

其他参数
--set-selection,指定对输入图像进行裁剪。特别是当RKISP1的前级大小发生变化时要保证selection不大于前级输出大小。RKCIF的裁剪则是通过--set-crop参数设置的
--stream-poll,该选项指示v4l2-ctl采用异步IO,即在dqbuf前先用select等等帧数据完成,从而保证dqbuf不阻塞。否则dqbuf将会阻塞直到有数据帧到来
  1. ffplay命令选项
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
# 基本格式: ffplay [选项] [‘输入文件’]

-x width # 强制显示宽带
-y height # 强制显示高度
-video_size size # 设置帧尺寸 设置帧尺寸大小。
# 适用于类似原始YUV等没有包含帧大小(WxH)的视频。
# 例如:ffplay -pixel_format yuv420p -video_size 320x240 -framerate 5 yuv420p_320x240.yuv

-pixel_format format # 设置像素格式
-volume vol # 设置起始音量。音量范围[0 ~100]
-window_title title # 设置窗口标题(默认为输入文件名)
-loop number # 设置播放循环次数
-showmode mode # 设置显示模式,可用的模式值:0 显示视频,1 显示音频波形,2 显示音频频谱。缺省为0,如果视频不存在则自动选择2
-vf filtergraph # 设置视频滤镜
-af filtergraph # 设置音频滤镜
-f fmt # 强制使用设置的格式进行解析。比如-f s16le

-fs # 以全屏模式启动
-an # 禁用音频(不播放声音)
-vn # 禁用视频(不播放视频)
-sn # 禁用字幕(不显示字幕)
-nodisp # 关闭图形化显示窗口,视频将不显示
-noborder # 无边框窗口

-t duration # 设置播放视频/音频长度,时间单位如 -ss选项
-ss pos # 跳转到指定的位置,注意时间单位:
# 比如:'55' 55 seconds, '12:03:45' ,12 hours, 03 minutes and 45 seconds, '23.189' 23.189 second

-bytes # 按字节进行跳转(0=off 1=on -1=auto)。
-seek_interval interval # 自定义左/右键定位拖动间隔(以秒为单位),默认值为10秒(代码没有看到实现)

# PC上显示图片例子:ffplay -f rawvideo -pixel_format nv12 -video_size 480x480 /tmp/nv12.yuv
  1. ffmpeg部分参数
1
2
3
4
5
6
7
8
-f <format>		# 指定格式,-i之前指示输入文件格式,-i之后指定输出文件格式。eg. mpegts(普通文件), v4l2, x11grab, alsa
-i <filename> # 指定输入文件名。eg. abc.mp4,/dev/video0(摄像头),:0.0(屏幕的(0,0)偏移处),pulse(麦克风)
-ss xxx # 从指定时间开始(秒)(输入为普通文件时常用)
-t xxx # 指定时长(秒)(输入为普通文件时常用)
-re # 按照帧率发送,作为推流工具时需要加入此参数,否则按最高速率不停发送
-map 0:0 # map本身指代一路输出流(后方跟输出文件),指示第0个输入的第0个stream(可通过ffprobe查看)
-y # 覆盖已有输出文件
-fs <limit_size> # 设置大小上限

显示到屏幕

1
2
3
4
5
6
7
8
9
10
11
# 分别提供命令gst-launch-1.0和参数fbdevsink及v4l2src的支持
apk add gstreamer-tools gst-plugins-bad gst-plugins-good

# 在LCD屏幕上显示雪花测试
gst-launch-1.0 videotestsrc pattern=snow ! fbdevsink

# 在LCD屏幕上实时显示摄像头内容
gst-launch-1.0 v4l2src device=/dev/video11 ! video/x-raw,format=NV12,width=480,height=480 ! videoconvert ! fbdevsink

# 由于摄像头输出YUV格式的图形,但是FB又只能接受RGB格式的图像,所以中间接入了一个convert环节
# 这里从NV21(YUV的一种排列格式), 经过convertor转换后变成了RGB格式,这个时候FB就可以正常显示了

其他程序推流

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
# Alpine下编译支持NV12的ustreamer
date -s "2024-04-09 15:48:00" # 设置下时间,不然老是警告
apk add git file gcc make libc-dev libevent-dev libjpeg-turbo-dev libbsd-dev libmd-dev

git clone -b rk3588-b https://github.com/Vincent056/ustreamer.git
cd ustreamer && make

Alpine:~/ustreamer# ldd src/ustreamer.bin
/lib/ld-musl-armhf.so.1 (0xa6f46000)
libjpeg.so.8 => /usr/lib/libjpeg.so.8 (0xa6e7b000)
libevent-2.1.so.7 => /usr/lib/libevent-2.1.so.7 (0xa6e32000)
libevent_pthreads-2.1.so.7 => /usr/lib/libevent_pthreads-2.1.so.7 (0xa6e2f000)
libbsd.so.0 => /usr/lib/libbsd.so.0 (0xa6e1f000)
libc.musl-armhf.so.1 => /lib/ld-musl-armhf.so.1 (0xa6f46000)
libmd.so.0 => /usr/lib/libmd.so.0 (0xa6e12000)
Alpine:~/ustreamer# ldd src/ustreamer-dump.bin
/lib/ld-musl-armhf.so.1 (0xa6e92000)
libjpeg.so.8 => /usr/lib/libjpeg.so.8 (0xa6e1e000)
libc.musl-armhf.so.1 => /lib/ld-musl-armhf.so.1 (0xa6e92000)
Alpine:~/ustreamer/src#


# 静态编译(可以移动到其他系统使用,现在除去这些依赖)
apk add git file gcc make libc-dev libevent-static libjpeg-turbo-static libbsd-static libmd-dev

# 修改 ustreamer/src/Makefile 内容
_LDFLAGS = $(LDFLAGS) -static
_COMMON_LIBS = -l:libm.a -l:libjpeg.a -l:libpthread.a -l:librt.a
_USTR_LIBS = $(_COMMON_LIBS) -l:libevent.a -l:libevent_pthreads.a -l:libbsd.a -l:libmd.a

Alpine:~/ustreamer# ldd src/ustreamer.bin
/lib/ld-musl-armhf.so.1: src/ustreamer.bin: Not a valid dynamic program
Alpine:~/ustreamer# file src/ustreamer.bin
src/ustreamer.bin: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), statically linked, BuildID[sha1]=ea1690bfc3227241690d061787e31c9a0004c88f, with debug_info, not stripped
Alpine:~/ustreamer#


# 软件ustreamer的使用
ustreamer --host=0.0.0.0 --port=80 --device=/dev/video11 --quality=80 --resolution=480x480