RK3588 MIPI 采集与硬件编码推流实战
在嵌入式视觉开发中,打通从摄像头采集到网络推流的完整链路往往涉及多个底层组件的协作。本文基于 RK3588 平台,分享一套经过验证的方案:MIPI 摄像头 -> 硬件 ISP -> OpenCV(AI 处理) -> 硬件 H.264 编码 -> 局域网 WebRTC 超低延迟推流与客户端录制。
整体架构思路
主要功能使用 Python 实现,核心流程如下:
- 画面采集:使用 GStreamer 直接对接底层驱动,利用 RK3588 的硬件 ISP 把 MIPI RAW 数据转成彩色的缩小画面。
- OpenCV 处理:OpenCV 拿到图片后,可以进行图像增强或 AI 推理等处理。
- 硬件编码推流:将处理后的画面交给
mpph264enc(瑞芯微硬件编码器)压缩,推给本机的流媒体服务器。 - 终端分发:使用轻量级的
MediaMTX作为流媒体服务器,客户端通过 WebRTC 协议实现网页端秒开与超低延迟观看。
第一步:环境准备
首先确认你的摄像头节点(例如单摄时可能是 /dev/video11)。确保安装了带 GStreamer 支持的 OpenCV 和相关插件。注意 PyPI 上的 opencv-python 默认不支持 gstreamer,建议直接使用系统环境的 opencv 或手动编译。
sudo apt-get update
sudo apt-get install python3-opencv
sudo apt-get install gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-rtsp
第二步:部署轻量级流媒体服务器 (MediaMTX)
建议在板子上运行服务器,这样客户端无需额外配置。下载 ARM64 版本并运行:
wget https://github.com/bluenviron/mediamtx/releases/download/v1.16.1/mediamtx_v1.16.1_linux_arm64.tar.gz
tar -zxvf mediamtx_v1.16.1_linux_arm64.tar.gz
./mediamtx
启动成功后应看到类似以下输出,表明各服务端口已监听:
INF MediaMTX v1.16.1, linux, arm64
INF [RTSP] listener opened on :8554 (TCP/RTSP), :8000 (UDP/RTP), :8001 (UDP/RTCP)
INF [WebRTC] listener opened on :8889 (HTTP), :8189 (ICE/UDP)
保持此终端不关闭,后续操作可在其他终端进行。
第三步:核心 Python 脚本
新建一个 Python 脚本 stream.py。这段代码包含了降分辨率、防缓存延迟和调用 MPP 硬件编码的核心逻辑。
import cv2
import time
class FPSCounter:
():
.timestamps = []
.buffer_size = buffer_size
():
current_time = time.time()
.timestamps.append(current_time)
(.timestamps) > .buffer_size:
.timestamps.pop()
():
(.timestamps) < :
time_span = .timestamps[-] - .timestamps[]
time_span <= :
((.timestamps) - ) / time_span
cap_pipeline = (
)
push_pipeline = (
)
cap = cv2.VideoCapture(cap_pipeline, cv2.CAP_GSTREAMER)
cap.isOpened():
()
exit()
out = cv2.VideoWriter(push_pipeline, cv2.CAP_GSTREAMER, , , (, ))
out.isOpened():
()
exit()
()
:
fps_counter = FPSCounter()
:
ret, frame = cap.read()
ret:
()
fps_counter.update()
fps = fps_counter.get_fps()
cv2.putText(frame, , (, ), cv2.FONT_HERSHEY_SIMPLEX, , (, , ), )
cv2.putText(frame, , (, ), cv2.FONT_HERSHEY_SIMPLEX, , (, , ), )
out.write(frame)
KeyboardInterrupt:
()
:
cap.release()
out.release()

