摄像头应用
目标平台: RK3576 | NPU 算力: 6 TOPS | 文档版本: V1.0
适用板型: C-3576BQ 核心板 + M4-R2 底板
最后更新: 2026-10-23
1. 概述
1.1 文档定位
本文档面向使用 RK3576 Linux 平台的开发者,涵盖 MIPI CSI 摄像头和 USB 摄像头(UVC)的接入、调试与应用开发。内容基于 V4L2 框架和 Rkisp 图像处理流水线,适用于 ShimetaPi M4-R2 V10 底板配合 C-3576BQ 核心板的硬件环境。
1.2 RK3576 摄像头子系统架构
┌─────────────────────────────────────────────────────────────────┐
│ Application Layer │
│ ┌───────────┐ ┌──────────┐ ┌────────────┐ ┌─────────────┐ │
│ │ GStreamer │ │ FFmpeg │ │ libcamera │ │ 自定义 App │ │
│ └─────┬─────┘ └────┬─────┘ └─────┬──────┘ └──────┬──────┘ │
│────────┼──────────────┼──────────────┼────────────────┼─────────│
│ V4L2 Framework │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ /dev/video* v4l2-ctl media-ctl libv4l2 │ │
│ └──────────┬───────────────────────────────────────────────┘ │
│─────────────┼───────────────────────────────────────────────────│
│ ┌──────────▼──────────┐ ┌──────────────────────────┐ │
│ │ MIPI CSI-2 │ │ USB (UVC) │ │
│ │ csi@<base_addr> │ │ xhci-hcd / ehci-hcd │ │
│ │ ┌──────────────┐ │ │ ┌──────────────────┐ │ │
│ │ │ DPHY │ │ │ │ UVC Driver │ │ │
│ │ └──────┬───────┘ │ │ └────────┬─────────┘ │ │
│ └─────────┼───────────┘ └───────────┼──────────────┘ │
│ ┌─────────▼────────────────────────────────▼──────────────┐ │
│ │ Rkisp (ISP) │ │
│ │ ┌────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ │
│ │ │ 3A │ │ Demosaic │ │ Gamma │ │ Noise │ │ │
│ │ │ (AE/ │ │ │ │ Correct │ │ Reduction │ │ │
│ │ │ AF/ │ │ │ │ │ │ │ │ │
│ │ │ AWB) │ │ │ │ │ │ │ │ │
│ │ └────────┘ └──────────┘ └──────────┘ └──────────────┘ │ │
│ │ └───────────────────────┬─────────────────────────────────┘ │
│ │ ┌───────────────────────▼─────────────────────────────────┐ │
│ │ │ V4L2 Video Device (output) │ │
│ │ └─────────────────────────────────────────────────────────┘ │
│ └─────────────────────────────────────────────────────────────────┘说明:图中
csi@<base_addr>为通用结构占位符,RK3576 的 CSI 控制器节点名与寄存器基地址以实际发布的 RK3576 SDK 设备树为准(待板上确认)。
1.3 支持的摄像头接口
| 接口类型 | 驱动框架 | 分辨率范围 | 典型帧率 | 说明 |
|---|---|---|---|---|
| MIPI CSI-2 (4-lane) | V4L2 + Rkisp | 取决于传感器 | 待板上验证 | 通过 CSI-2 DPHY 接收串行数据 |
| USB 3.0 UVC | V4L2 + UVC | 取决于传感器 | 待板上验证 | 即插即用,免驱动安装 |
| USB 2.0 UVC | V4L2 + UVC | 取决于传感器 | 待板上验证 | 带宽受限 |
M4-R2 规格书标注板卡支持 1 路 MIPI Camera 输入(30pin/0.5mm FPC),最高支持 1600W 分辨率。具体可用分辨率与帧率取决于接入的传感器型号,需在板端实测(待板上验证)。
1.4 适用范围
- SoC: RK3576
- 核心板: C-3576BQ
- 底板: ShimetaPi M4-R2 V10
- 内核: Linux 6.1
- 发行版: Debian / Ubuntu(以实际发布的 RK3576 SDK 为准)
2. 硬件准备
2.1 MIPI CSI 摄像头连接
2.1.1 CSI 接口定义
M4-R2 底板提供 1 路 MIPI Camera 接口(30pin/0.5mm 间距立式 FPC 插座),接口定义参考 S-04 底板资料:
| 信号名称 | 引脚功能 | 说明 |
|---|---|---|
| CSI_CLK_P/N | MIPI 时钟差分对 | DPHY 时钟通道 |
| CSI_DATA0_P/N ~ CSI_DATA3_P/N | MIPI 数据差分对 Lane0-3 | 串行数据通道 |
| CSI_SCL / CSI_SDA | I2C 控制 | 传感器 I2C 总线 |
| CSI_RST | 复位 GPIO | 传感器硬件复位 |
| CSI_PWR | 电源使能 GPIO | 传感器上电控制 |
具体引脚编号与顺序以 M4-R2 底板规格书/底板资料为准(S-01、S-04)。
2.1.2 硬件连接示意
C-3576BQ 核心板 ShimetaPi M4-R2 V10 底板
┌─────────────────┐ ┌─────────────────────┐
│ │ FPC 连接器 │ │
│ MIPI CSI-2 ───┼──────────────┼──► CSI 摄像头座 │
│ (4-lane) │ │ (30Pin FPC) │
│ │ │ │
│ I2C ─────────┼──────────────┼──► CSI_SCL / SDA │
│ │ │ │
│ GPIO ────────┼──────────────┼──► CSI_RST / PWR │
└─────────────────┘ └─────────────────────┘2.2 USB 摄像头连接
将 UVC 兼容的 USB 摄像头插入 M4-R2 底板的 USB 接口(1 路 USB3.0 OTG / 1 路 USB3.0 HOST / 3 路 USB2.0 HOST)即可。系统会在设备插入后自动加载 UVC 驱动。
2.3 常用摄像头型号参考
| 摄像头型号 | 接口 | 分辨率 | 说明 | 验证状态 |
|---|---|---|---|---|
| SC3338 | MIPI CSI 4-lane | 2304x1296 | 常见国产低成本传感器 | 待板上验证 |
| OV13850 | MIPI CSI 2-lane | 2104x1560 | 常见 MIPI 传感器 | 待板上验证 |
| Logitech C920 | USB 3.0 | 1920x1080 | 常见 UVC 摄像头,H.264 编码 | 待板上验证 |
| Logitech C270 | USB 2.0 | 1280x720 | 常见 UVC 摄像头,MJPEG | 待板上验证 |
以上型号为行业常用参考,具体是否适配需在 C-3576BQ + M4-R2 V10 板卡上实测(待板上验证)。传感器驱动的使能与 DTS 配置以实际发布的 RK3576 SDK 为准。
3. 软件准备
3.1 内核配置
确保内核已启用以下配置项:
# 查看当前内核配置
cat /boot/config-$(uname -r) | grep -E "V4L2|VIDEO|MEDIA|ISP|CAM"必需的内核配置(配置项名称以实际发布的 RK3576 SDK 内核为准):
CONFIG_VIDEO=y
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_VIDEO_ROCKCHIP=y
CONFIG_VIDEO_ROCKCHIP_ISP=y
CONFIG_VIDEO_ROCKCHIP_CIF=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CAMERA_SUPPORT=y
CONFIG_VIDEOBUF2_DMA_CONTIG=y
CONFIG_USB_VIDEO_CLASS=y
CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y3.2 用户空间工具安装
sudo apt update
sudo apt install -y \
v4l-utils media-ctl \
libv4l-dev libjpeg-dev libusb-1.0-0-dev \
gstreamer1.0-tools gstreamer1.0-plugins-bad \
gstreamer1.0-plugins-ugly gstreamer1.0-plugins-good \
ffmpeg libcamera-dev libcamera-tools3.3 libcamera 环境确认
# 列出 libcamera 识别的设备
libcamera-hello --list-cameras
# 预期输出(示例,传感器名称以实际接入为准)
# Available cameras
# -----------------
# 0 : imx<xxx> <i2c-bus>-<addr>
# Modes: 'SRGGB10_CSI2P' : <width>x<height> [<fps> fps]3.4 ISP 固件检查
# 确认 ISP 固件文件存在
ls /lib/firmware/rkisp/
# 应包含 rkisp 相关 bin 文件
# 确认 Rkisp 设备节点
ls /dev/media*3.5 环境验证脚本
#!/bin/bash
# camera_env_check.sh — 摄像头环境快速检查
echo "=== RK3576 Camera Environment Check ==="
echo "[1] Kernel: $(uname -r)"
echo "[2] V4L2: $(ls /dev/video* 2>/dev/null || echo 'none')"
echo "[3] Media: $(ls /dev/media* 2>/dev/null || echo 'none')"
echo "[4] USB: $(lsusb | grep -iE 'camera|webcam|uvc' || echo 'none')"
echo "[5] libcamera: $(libcamera-hello --list-cameras 2>&1 | head -3)"
echo "[6] ISP firmware: $(ls /lib/firmware/rkisp/ 2>/dev/null || echo 'missing')"
echo "[7] rkisp module: $(lsmod | grep rkisp || echo 'not loaded')"
echo "=== Done ==="4. 操作步骤
4.1 MIPI CSI 摄像头调试流程
4.1.1 检查设备注册
v4l2-ctl --list-devices
# 预期输出(示例,平台前缀以实际 SDK 为准)
# rkisp-vir0 (platform:<base_addr>):
# /dev/video0 /dev/video1 /dev/video2 /dev/video3 /dev/media04.1.2 使用 media-ctl 配置 pipeline
# 查看 media topology
media-ctl -p -d /dev/media0
# 配置 MIPI CSI pipeline(传感器实体名以实际设备为准)
media-ctl -d /dev/media0 \
-V "'<sensor>':0 [fmt:SRGGB10_CSI2P/<width>x<height>]" \
-V "'rkisp1_input':0 [fmt:SRGGB10_CSI2P/<width>x<height>]" \
-V "'rkisp1_selfpath':0 [fmt:NV12/<width>x<height>]"4.1.3 使用 v4l2-ctl 捕获图像
# 查询支持的格式
v4l2-ctl -d /dev/video0 --list-formats-ext
# 设置分辨率和帧率
v4l2-ctl -d /dev/video0 \
--set-fmt-video=width=2304,height=1296,pixelformat=SRGGB10 \
--set-parm=30
# 单帧捕获
v4l2-ctl -d /dev/video0 \
--set-fmt-video=width=2304,height=1296,pixelformat=NV12 \
--stream-mmap --stream-count=1 \
--stream-to=/tmp/test_frame.nv12
# 转换为可查看格式
ffmpeg -f rawvideo -pixel_format nv12 -video_size 2304x1296 \
-i /tmp/test_frame.nv12 -frames:v 1 /tmp/test_frame.jpg -y4.1.4 持续录像
# 录像 10 秒(300 帧)
v4l2-ctl -d /dev/video0 \
--set-fmt-video=width=1920,height=1080,pixelformat=NV12 \
--set-parm=30 \
--stream-mmap --stream-count=300 \
--stream-to=/tmp/capture.nv12
# 转换为 MP4
ffmpeg -f rawvideo -pixel_format nv12 -video_size 1920x1080 \
-framerate 30 -i /tmp/capture.nv12 \
-c:v libx264 -pix_fmt yuv420p /tmp/capture.mp4 -y上述分辨率/帧率是否可达取决于接入的传感器与 ISP 配置,需在板端实测(待板上验证)。
4.2 USB 摄像头调试流程
4.2.1 识别与格式查询
# 检查 USB 设备
lsusb
# Bus 001 Device 003: ID 046d:0825 Logitech, Inc. Webcam C270
# 查看分配的设备节点
v4l2-ctl --list-devices
# 查询 USB 摄像头支持的所有格式
v4l2-ctl -d /dev/video4 --list-formats-ext4.2.2 USB 摄像头捕获测试
# MJPEG 格式捕获
v4l2-ctl -d /dev/video4 \
--set-fmt-video=width=1920,height=1080,pixelformat=MJPG \
--stream-mmap --stream-count=1 \
--stream-to=/tmp/usb_frame.jpg4.3 使用 GStreamer 构建视频流水线
4.3.1 MIPI CSI 预览
# Wayland 桌面环境
gst-launch-1.0 v4l2src device=/dev/video0 \
! video/x-raw,width=1920,height=1080,framerate=30/1 \
! videoconvert ! autovideosink
# 无桌面环境 DRM 输出
gst-launch-1.0 v4l2src device=/dev/video0 \
! video/x-raw,width=1920,height=1080,framerate=30/1 \
! videoconvert ! kmssink4.3.2 硬件编码录像
# RK3576 硬件编码录制 H.264(M4-R2 支持 H.264/H.265 硬件编码)
gst-launch-1.0 v4l2src device=/dev/video0 \
! video/x-raw,width=1920,height=1080,framerate=30/1 \
! videoconvert \
! v4l2h264enc extra-controls="encode,video_bitrate=4000000" \
! h264parse ! matroskamux \
! filesink location=/tmp/camera_recording.mkv
# 同时预览 + 录像(tee 分流)
gst-launch-1.0 v4l2src device=/dev/video0 \
! video/x-raw,width=1920,height=1080,framerate=30/1 \
! tee name=t \
t. ! queue ! videoconvert ! autovideosink \
t. ! queue ! videoconvert \
! v4l2h264enc extra-controls="encode,video_bitrate=4000000" \
! h264parse ! matroskamux \
! filesink location=/tmp/recording.mkv4.3.3 MJPEG 推流
# USB 摄像头 MJPEG TCP 推流
gst-launch-1.0 v4l2src device=/dev/video4 \
! video/x-raw,width=1920,height=1080,framerate=30/1 \
! jpegenc quality=85 \
! multipartmux boundary="--boundary" \
! tcpserversink host=0.0.0.0 port=8080
# 客户端拉流
ffplay http://<server-ip>:80804.4 使用 libcamera 进行摄像头操作
# 列出设备
libcamera-hello --list-cameras
# 预览(3 秒)
libcamera-hello -t 3000
# 拍照
libcamera-still -o /tmp/photo.jpg --width 2304 --height 1296
# 录像(10 秒 H.264)
libcamera-vid -o /tmp/video.h264 \
--width 1920 --height 1080 \
--framerate 30 --timeout 10000 --codec h2644.5 Python + OpenCV 摄像头应用
#!/usr/bin/env python3
"""camera_capture.py — RK3576 摄像头捕获示例"""
import cv2
import sys
import time
def main():
device = int(sys.argv[1]) if len(sys.argv) > 1 else 0
cap = cv2.VideoCapture(device)
if not cap.isOpened():
print(f"Error: Cannot open camera {device}")
sys.exit(1)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080)
cap.set(cv2.CAP_PROP_FPS, 30)
print(f"Camera {device}: {int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))}x"
f"{int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))} @ "
f"{cap.get(cv2.CAP_PROP_FPS):.0f}fps")
frame_count = 0
start_time = time.time()
while True:
ret, frame = cap.read()
if not ret:
break
frame_count += 1
if time.time() - start_time >= 1.0:
print(f"FPS: {frame_count:.1f}")
frame_count = 0
start_time = time.time()
cv2.imshow("RK3576 Camera", frame)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
elif key == ord('s'):
ts = time.strftime("%Y%m%d_%H%M%S")
cv2.imwrite(f"/tmp/snapshot_{ts}.jpg", frame)
cap.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
main()5. 代码详解
5.1 V4L2 视频采集流程
┌─────────────────────────────────────────────────────────────┐
│ V4L2 Video Capture Flow │
├─────────────────────────────────────────────────────────────┤
│ 1. open("/dev/video0") │
│ 2. ioctl(VIDIOC_QUERYCAP) -- 查询设备能力 │
│ 3. ioctl(VIDIOC_S_FMT) -- 设置采集格式 │
│ 4. ioctl(VIDIOC_REQBUFS) -- 申请缓冲区 │
│ 5. ioctl(VIDIOC_QUERYBUF) + mmap() -- 映射缓冲区 │
│ 6. ioctl(VIDIOC_QBUF) -- 缓冲区入队 │
│ 7. ioctl(VIDIOC_STREAMON) -- 开始视频流 │
│ 8. loop: │
│ - ioctl(VIDIOC_DQBUF) -- 取出已填充的缓冲区 │
│ - process(frame_data) -- 处理帧数据 │
│ - ioctl(VIDIOC_QBUF) -- 重新入队 │
│ 9. ioctl(VIDIOC_STREAMOFF) -- 停止视频流 │
│ 10. munmap() + close() -- 释放资源 │
└─────────────────────────────────────────────────────────────┘5.2 MMAP 模式采集示例
/*
* v4l2_capture_mmap.c — RK3576 V4L2 MMAP 模式摄像头采集
* 编译: aarch64-linux-gnu-gcc -o v4l2_capture v4l2_capture_mmap.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#define DEVICE_PATH "/dev/video0"
#define BUFFER_COUNT 4
#define IMG_WIDTH 1920
#define IMG_HEIGHT 1080
struct buffer { void *start; size_t length; };
static int xioctl(int fd, int req, void *arg) {
int r;
do { r = ioctl(fd, req, arg); } while (r == -1 && errno == EINTR);
return r;
}
int main(int argc, char *argv[]) {
int fd;
struct v4l2_capability cap;
struct v4l2_format fmt;
struct v4l2_requestbuffers req;
struct v4l2_buffer buf;
struct buffer *buffers;
unsigned int i;
const char *device = (argc > 1) ? argv[1] : DEVICE_PATH;
/* 打开设备 */
fd = open(device, O_RDWR | O_NONBLOCK);
if (fd < 0) { perror("open"); return 1; }
/* 查询能力 */
if (xioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) { perror("QUERYCAP"); goto done; }
printf("Device: %s Driver: %s Bus: %s\n", cap.card, cap.driver, cap.bus_info);
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) ||
!(cap.capabilities & V4L2_CAP_STREAMING)) {
fprintf(stderr, "Device does not support capture/streaming\n");
goto done;
}
/* 设置格式 */
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = IMG_WIDTH;
fmt.fmt.pix.height = IMG_HEIGHT;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_NV12;
fmt.fmt.pix.field = V4L2_FIELD_NONE;
if (xioctl(fd, VIDIOC_S_FMT, &fmt) < 0) { perror("S_FMT"); goto done; }
printf("Format: %dx%d bpl=%d size=%d\n",
fmt.fmt.pix.width, fmt.fmt.pix.height,
fmt.fmt.pix.bytesperline, fmt.fmt.pix.sizeimage);
/* 申请缓冲区 */
memset(&req, 0, sizeof(req));
req.count = BUFFER_COUNT;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if (xioctl(fd, VIDIOC_REQBUFS, &req) < 0) { perror("REQBUFS"); goto done; }
/* 映射缓冲区 */
buffers = calloc(req.count, sizeof(*buffers));
for (i = 0; i < req.count; i++) {
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (xioctl(fd, VIDIOC_QUERYBUF, &buf) < 0) { perror("QUERYBUF"); goto done; }
buffers[i].length = buf.length;
buffers[i].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, buf.m.offset);
if (buffers[i].start == MAP_FAILED) { perror("mmap"); goto done; }
}
/* 入队并启动流 */
for (i = 0; i < req.count; i++) {
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
xioctl(fd, VIDIOC_QBUF, &buf);
}
{
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
xioctl(fd, VIDIOC_STREAMON, &type);
}
printf("Streaming... capturing one frame\n");
/* 取出一帧并保存 */
{
fd_set rfds; struct timeval tv;
FD_ZERO(&rfds); FD_SET(fd, &rfds);
tv.tv_sec = 5; tv.tv_usec = 0;
if (select(fd + 1, &rfds, NULL, NULL, &tv) > 0) {
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (xioctl(fd, VIDIOC_DQBUF, &buf) == 0) {
FILE *fp = fopen("/tmp/frame.raw", "wb");
if (fp) {
fwrite(buffers[buf.index].start, 1, buf.bytesused, fp);
fclose(fp);
printf("Saved /tmp/frame.raw (%u bytes)\n", buf.bytesused);
}
xioctl(fd, VIDIOC_QBUF, &buf);
}
}
}
/* 停止流并释放 */
{
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
xioctl(fd, VIDIOC_STREAMOFF, &type);
}
for (i = 0; i < req.count; i++)
if (buffers[i].start != MAP_FAILED)
munmap(buffers[i].start, buffers[i].length);
free(buffers);
done:
close(fd);
return 0;
}5.3 Rkisp ISP 图像处理流程
MIPI CSI-2 Input (RAW Bayer)
│
▼
┌───────────────┐
│ Black Level │ ──► Defect Pixel Correction
│ Correction │
└───────┬───────┘
▼
┌───────────────┐
│ Lens Shading │ ──► Demosaic (Bayer → RGB)
│ Correction │
└───────┬───────┘
▼
┌───────────────┐
│ White Balance│ ──► Color Correction Matrix (CCM)
│ (AWB) │
└───────┬───────┘
▼
┌───────────────┐
│ Auto Exposure│ ──► Gamma Correction
│ (AE) │
└───────┬───────┘
▼
┌───────────────┐
│ Noise Reduc. │ ──► Edge Enhancement
│ (NR) │
└───────┬───────┘
▼
V4L2 Video Output (NV12 / YUV420)RK3576 Rkisp 的 3A(AE/AWB/AF)算法通过 camera_engine_rkaiq 库实现。ISP tuning 文件通常位于 /etc/camera/rkisp/,每个传感器有独立的配置文件(以实际发布的 RK3576 SDK 为准)。
5.4 libcamera 集成示例
#!/usr/bin/env python3
"""libcamera_integration.py — RK3576 libcamera Python 集成示例"""
import subprocess
import os
class RK3576Camera:
"""RK3576 libcamera 摄像头封装"""
def __init__(self, index=0):
self.index = index
result = subprocess.run(
['libcamera-hello', '--list-cameras'],
capture_output=True, text=True
)
if 'No cameras available' in result.stdout:
raise RuntimeError("No cameras detected")
print(f"Camera {index} ready")
def capture_photo(self, path, w=1920, h=1080):
subprocess.run([
'libcamera-still', '-o', path,
'--width', str(w), '--height', str(h),
'--immediate', '-n'
], check=True)
print(f"Saved: {path} ({os.path.getsize(path)} bytes)")
def record_video(self, path, duration=10, w=1920, h=1080, codec='h264'):
subprocess.run([
'libcamera-vid', '-o', path,
'--width', str(w), '--height', str(h),
'--framerate', '30', '--timeout', str(duration * 1000),
'--codec', codec, '-n'
], check=True)
print(f"Saved: {path} ({os.path.getsize(path)} bytes)")
def test_pipeline(self):
r = subprocess.run(['libcamera-hello', '-t', '1000'],
capture_output=True, text=True)
return r.returncode == 0
if __name__ == "__main__":
cam = RK3576Camera(0)
print("Pipeline test:", "OK" if cam.test_pipeline() else "FAIL")
cam.capture_photo('/tmp/photo.jpg')
cam.record_video('/tmp/video.h264', duration=5)6. 常见问题
6.1 MIPI CSI 摄像头无法识别
排查步骤:
# 检查内核日志
dmesg | grep -iE "csi|isp|sensor|camera"
# 检查 I2C 总线(CSI 摄像头所在 I2C 总线以实际 DTS 为准)
i2cdetect -y <bus>
# 检查驱动模块
lsmod | grep -E "rkisp|rkcif|v4l2"
# 检查 DTS 设备树
find /sys/firmware/devicetree/base/ -name "*csi*"常见原因: FPC 排线未正确插入、传感器供电异常、I2C 地址配置错误、DTS 未配置 CSI 控制器、传感器驱动未编译进内核。
6.2 USB 摄像头无法识别
排查步骤:
lsusb # 确认 USB 设备枚举
dmesg | tail -30 # 查找 UVC 驱动加载信息
lsmod | grep uvcvideo # 检查驱动
sudo modprobe uvcvideo # 手动加载
dmesg | grep -i "over-current" # 检查供电常见原因: USB 端口供电不足、线缆质量差、UVC 驱动未编译进内核。注意 M4-R2 采用 5V/2A 供电(空载最小 1000mA),接入大功耗 USB 摄像头时请确认供电余量。
6.3 采集图像花屏或色彩异常
排查步骤:
v4l2-ctl -d /dev/video0 --list-formats-ext # 确认像素格式
dmesg | grep -iE "dphy|lane|clock" # 检查 DPHY
# 降低分辨率测试
v4l2-ctl -d /dev/video0 --set-fmt-video=width=640,height=480常见原因: 像素格式不匹配、MIPI DPHY 时钟超限、ISP 未正确配置、数据通道数量不匹配。
6.4 帧率不足
排查步骤:
# 检查实际帧率
v4l2-ctl -d /dev/video0 --stream-mmap --stream-count=300 \
--stream-to=/dev/null 2>&1 | grep "fps"
top -bn1 | head -5 # 系统负载
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq # CPU 频率常见原因: USB 带宽限制、ISP 处理能力不足、CPU 负载过高。
6.5 libcamera 无法找到设备
v4l2-ctl --list-devices # V4L2 是否正常
LIBCAMERA_LOG_LEVELS=* libcamera-hello --list-cameras # 详细日志
ls /etc/libcamera/ipa/rkisp* # IPA 配置常见原因: libcamera IPA 配置缺失、media 设备节点权限不足、Rkisp 驱动未正确注册。
6.6 GStreamer 管道报错
gst-inspect-1.0 v4l2src # 检查插件
gst-inspect-1.0 | grep -i h264 # 可用编码器
gst-launch-1.0 videotestsrc ! autovideosink # 最简测试
echo $WAYLAND_DISPLAY # Wayland 环境7. 相关文档
| 文档名称 | 路径 | 说明 |
|---|---|---|
| 显示框架 | 显示框架 | DRM/KMS 显示框架 |
| 视频编解码 (MPP) | 视频编解码(MPP) | MPP 视频编解码框架 |
| 音频开发与 ALSA | 音频开发与ALSA | ALSA 音频框架 |
| RGA 图像处理 | RGA图像处理 | RGA 2D 图形加速 |
| 人脸检测与识别 | 人脸检测与识别 | 基于摄像头的 NPU 应用 |
| OCR 文字识别 | OCR文字识别 | 基于摄像头的 NPU 应用 |
