RK3588 WebRTC 实时流 Segmentation fault 分析:从 RGA 错误定位到 GStreamer 视频转换修复
本文记录一次 RK3588 WebRTC 实时流启动后播放器崩溃的完整定位过程:问题最终并非来自 MPP 编解码,而是 Rockchip 修改版 GStreamer 视频转换库中的 RGA 加速路径。
最终根因:Rockchip 修改版 libgstvideo-1.0.so 在 GST_VIDEO_CONVERT_USE_RGA=1 时使用 RGA 1.10.1 执行视频格式转换。 对于可见分辨率为 1280x718、硬件 stride 高度为 720 的解码缓冲, RGA 的 NV12 到 I420 转换失败并破坏进程内存,最终触发 Segmentation fault。
一、问题背景
我用MYZR-RK3588-EK360(官网为:MYZR-RK3588-EK360 — 明远智睿的文档 文档)生成WebRTC网页实时流,效果如下:

网页实时流通过GStreamer的webrtcbin插件实现。webrtcbin负责:RTP封装、SRTP加密、DTLS握手、ICE穿透、NAT处理、SDP offer/answer、数据通道.....这样这些功能就不用用户自己实现了。webrtcbin的官方文档为:webrtcbin
RK3588 实时流系统同时承担物理 HDMI 显示和浏览器 WebRTC 分发。视频文件或采集输入先由 MPP 硬件解码为 NV12,播放器再把同一帧送往 HDMI 和网页流两条不同路径。收到 streamControl(播放器的启流控制消息)后,板端播放器会为指定通道启动网页实时流。
{
"messageType": "streamControl",
"payload": "{\"channelIndex\":1}"
}
本文中的 rk3588_gst_player 是运行在 RK3588 上的 GStreamer 播放器进程;streamControl 是请求它启动实时流的控制消息。
整体架构如下:
硬件解码后的原始视频
|
v
MPP 解码
|
v
NV12
|
+------------------+
| |
v v
kmssink WebRTC 编码
HDMI 输出 |
v
H.264 Encoder
|
v
浏览器播放
解码后的原始音频
|
+-- tee --> alsasink(物理 HDMI)
|
+-- interaudiosink --> opusenc --> WebRTC
HDMI 显示只需要 NV12;网页流还需要把视频送入编码器并通过网络发送,因此两条路径的格式和内存要求并不相同。音频还可以沿独立的 DEP(Dante 音频输出服务)路径输出。出现问题的素材为:
| 文件 | 复仇者联盟4-单音轨.mp4 |
|---|---|
| 视频编码 | H.264 |
| 可见分辨率 | 1280x718 |
| 硬件解码 stride | 1280x720 |
| 帧率 | 约 29.97 fps |
二、RGA 是什么
RGA(Raster Graphic Accelerator)是 Rockchip 提供的 2D 硬件加速模块,擅长执行格式转换、图像缩放、色彩转换和图像搬运。本案例中的 NV12 → I420 本来属于 RGA 的典型使用场景。
问题在于,解码帧的可见高度是 718,底层缓冲的 stride 高度是 720。这种“可见尺寸”和“硬件对齐尺寸”不同的组合,触发了 RGA 1.10.1 的异常处理路径;错误最终表现为内存破坏,而不只是一次转换失败。
三、故障现象
HDMI 已正常显示画面时发送 streamControl,接口先返回成功:
[WebRTC-1] Shared H.264/Opus encoder started
[ChannelPlayer-1] ReloadPlaylist called
Response sent: {"code":200,"data":"{...streamControlReply...}","msg":"Success."}
播放器随后重建 HDMI pipeline,并在视频格式转换阶段输出:
Video sink: capsfilter caps=video/x-raw,format=NV12
! identity drop-allocation=true
! tee name=stream_video_tee
...
! videoconvert
! video/x-raw,format=I420
! intervideosink ...
rga_api version 1.10.1_[10]
RGA_BLIT fail: Invalid argument
rect[0, 0, 1280, 718, 1280, 720, 2560, 0]
rect[0, 0, 1280, 718, 1280, 718, 2816, 0]
Segmentation fault
这不是普通的 pipeline 协商失败。RGA 在失败路径中破坏了内存,除了播放器段错误外, 还可能导致控制台、SSH 或其他板端命令异常,只能重启板子恢复。
四、为什么 HDMI 正常,网页流崩溃
不开启网页流时,路径很短:
解码 → NV12 → kmssink → HDMI
开启网页流后,新增了格式转换和编码路径:
解码 → NV12 → videoconvert → I420 → MPP H.264 编码 → WebRTC → 浏览器
因此“HDMI 正常”只能证明解码和显示路径正常,不能证明新增的 WebRTC 转换路径也正常。这个案例的崩溃发生在 videoconvert 的 NV12 到 I420 转换阶段,而不是 MPP 解码阶段。
- 未开启网页流时,解码后的 NV12 主要送入
kmssink,素材可以正常显示。 streamControl启动共享 H.264/Opus 编码 pipeline。ChannelPlayer::ReloadPlaylist()中断旧 pipeline,并按当前播放位置重新开始。- 新 pipeline 增加网页流分支,需要将 NV12 转换成 I420 后送入
intervideosink。 - Rockchip 修改版
libgstvideo尝试用 RGA 加速该转换。 - 源画面可见高度为 718,但底层硬件缓冲按 720 行对齐。
- RGA 1.10.1 对这组参数返回
Invalid argument,随后发生内存破坏和段错误。
五、如何从日志定位 RGA 问题
看到 RGA_BLIT fail、Invalid argument 和 Segmentation fault 时,不要第一时间下结论说“MPP 坏了”。更可靠的顺序是:
- 确认是谁调用了 RGA:MPP 插件、
videoconvert,还是其他库。 - 确认哪个 pipeline 分支触发:HDMI、WebRTC 视频,还是音频。
- 核对输入输出 buffer 的格式、可见尺寸和 stride,寻找异常组合。
(一)从崩溃日志锁定 RGA 和特殊高度
首先从日志提取错误、pipeline 和尺寸信息:
rg -n "RGA|Segmentation|ERROR|Failed|streamControl|WebRTC|Video sink" player.log
关键证据不是单独的 Segmentation fault,而是它前面的两组矩形参数:
源:1280x718,stride 1280x720,格式 2560(NV12)
目标:1280x718,stride 1280x718,格式 2816(I420)
这说明崩溃与网页流新增的 NV12 到 I420 转换直接相关,而不是 HTTP 接口解析、节目单调度或 DEP 音频输出。
(二)第一阶段判断:怀疑 MPP 插件内部 RGA
仓库中的 Rockchip MPP 插件源码存在 RGA 转换函数:
rg -n "gst_mpp_use_rga|gst_mpp_dec_rga_convert|gst_mpp_enc_convert|RgaBlit" \
third_party/sources/gstreamer1-rockchip-master
对应源码包括:
gst/rockchipmpp/gstmpp.cgst/rockchipmpp/gstmppdec.cgst/rockchipmpp/gstmppenc.c
因此第一阶段采取了以下措施:
- 在解码器和 tee 之间固定 NV12 caps。
- 增加
identity drop-allocation=true,阻止下游分支的 allocation query 影响解码器。 - 设置
GST_MPP_NO_RGA=1。 - 使用
-Drga=disabled重新交叉编译libgstrockchipmpp.so。
(三)核对板端实际加载的插件
为了排除“改了源码但板子仍加载旧插件”,使用启动脚本运行 gst-inspect:
/root/Test/gst-test/use-gst-test.sh gst-inspect-1.0 mppvideodec
/root/Test/gst-test/use-gst-test.sh gst-inspect-1.0 mpph264enc
确认实际路径为:
/root/Test/gst-test/lib/gstreamer-1.0/libgstrockchipmpp.so
随后通过 SHA-256、ELF 依赖和字符串确认:
sha256sum /root/Test/gst-test/lib/gstreamer-1.0/libgstrockchipmpp.so
readelf -d libgstrockchipmpp.so
strings libgstrockchipmpp.so | grep "RGA disabled"
结果表明新 MPP 插件已部署,插件自身不再直接依赖 RGA,并包含:
RGA disabled at compile time
(四)关键转折:禁用 MPP RGA 后仍出现完全相同的 RgaBlit
重新测试后,日志仍在 videoconvert ! I420 处出现相同 RGA 错误。这证明:
MPP 插件确实包含一条 RGA 路径,但它不是本次最终仍在执行的 RGA 调用者。 仅设置 GST_MPP_NO_RGA 无法关闭 GStreamer 视频转换库里的另一条 RGA 路径。
阶段小结:到这里可以确认,问题已经从“MPP RGA”缩小到“GStreamer Base 视频转换 RGA”;下一步应扫描动态符号和依赖,寻找真正调用 RgaBlit 的库。
(五)扫描全部插件的动态符号和依赖
使用交叉工具链扫描目标运行时中的插件:
for f in third_party/rk3588-sdk/target/usr/lib/gstreamer-1.0/*.so; do
aarch64-none-linux-gnu-nm -D "$f" | rg "RgaBlit|c_RkRgaBlit"
done
同时检查动态依赖:
aarch64-none-linux-gnu-readelf -d libgstvideoconvertscale.so
aarch64-none-linux-gnu-readelf -d libgstvideo-1.0.so.0.2209.0
发现 videoconvert 元素本身位于 libgstvideoconvertscale.so,它通过 libgstvideo-1.0.so 完成真正的像素转换;后者直接依赖 librga.so.2,并含有 c_RkRgaBlit 未定义符号。
(六)从二进制证据回到源码
继续在 GStreamer Base 源码中搜索:
rg -n "RgaBlit|GST_VIDEO_CONVERT_USE_RGA" \
third_party/sources/gst1-plugins-base-1.22.9
最终定位到:
third_party/sources/gst1-plugins-base-1.22.9/
gst-libs/gst/video/video-converter.c
关键逻辑为:
buf = g_getenv ("GST_VIDEO_CONVERT_USE_RGA");
if (!buf || strcmp (buf, "1"))
return FALSE;
...
if (c_RkRgaBlit (&src_info, &dst_info, NULL) < 0)
return FALSE;
这段源码说明:只要 GST_VIDEO_CONVERT_USE_RGA 的值精确等于 1, videoconvert/videoscale 就会优先走 Rockchip RGA;否则回退到标准 GStreamer CPU 转换。
六、第一次修复为什么失败
第一次排查根据 MPP 插件源码中的 RGA 函数,设置了 GST_MPP_NO_RGA=1,并用 -Drga=disabled 重新编译 libgstrockchipmpp.so。这个方向并非完全错误:它确实关闭了 MPP 插件内部的一条 RGA 路径。
最初的假设:
mppvideodec / mpph264enc
|
v
RGA
实际调用链:
videoconvert → libgstvideo → librga.so.2 → RgaBlit()
重新部署后仍出现完全相同的 RgaBlit 错误,说明 MPP 没有调用这一次 RGA。真正的调用者是 Rockchip 修改版 libgstvideo-1.0.so:它在 GST_VIDEO_CONVERT_USE_RGA=1 时为 videoconvert 启用 RGA 加速。这是本案例最关键的误区:关闭 MPP RGA,不等于关闭 GStreamer Base 视频转换库的 RGA。
七、根本原因
根本原因由四个条件共同构成:
| 条件 | 作用 |
|---|---|
| 特殊视频高度 | 素材可见高度为 718,硬件解码缓冲按 720 行对齐。 |
| 网页流分支 | 开启网页流后需要执行 NV12 到 I420 的格式转换。 |
| Rockchip GStreamer 修改 | libgstvideo 增加了 RGA 加速路径。 |
| RGA 1.10.1 缺陷 | 无法安全处理该可见高度与 stride 组合,失败后产生内存破坏。 |
streamControl
|
v
重新创建 WebRTC pipeline
|
v
videoconvert
|
v
libgstvideo
|
v
GST_VIDEO_CONVERT_USE_RGA=1
|
v
librga.so.2 → RgaBlit()
|
v
Invalid argument → 内存破坏
|
v
Segmentation fault
这条链路把“网页流一启动就崩溃”与底层错误连接起来:控制消息只是触发器,真正的故障点是新增 WebRTC 视频分支中的格式转换。
八、修复方案
修复原则不是关闭 RK3588 的全部硬件能力,而是只关闭已证明不稳定的“视频格式转换 RGA 路径”。修复后仍保留 MPP 硬件解码、MPP 硬件编码和 HDMI 输出:
MPP Decoder
|
v
NV12
|\
| +---- HDMI / kmssink
|
+---- CPU videoconvert
|
v
I420
|
v
MPP H.264 Encoder
(一)应用层强制关闭 libgstvideo RGA
在 app/main.cpp 中,必须在 gst_init() 之前执行:
g_setenv("GST_VIDEO_CONVERT_USE_RGA", "0", TRUE);
gst_init(&argc, &argv);
应用启动时打印:
[GStreamer] CPU video conversion forced; libgstvideo RGA disabled
在应用内覆盖环境变量,可以防止用户直接运行二进制或外部 shell 环境意外设置为 1。
(二)启动脚本双重保护
scripts/use-gst-test.sh 和打包脚本生成的启动脚本均设置:
export GST_MPP_NO_RGA=1
export GST_VIDEO_CONVERT_USE_RGA=0
GST_MPP_NO_RGA=1:关闭 Rockchip MPP 插件内部的 RGA 转换。GST_VIDEO_CONVERT_USE_RGA=0:关闭libgstvideo中的 RGA 转换。
(三)MPP 插件在编译期禁用 RGA
新增 scripts/build-rockchip-gstreamer-plugin.sh,使用:
-Drockchipmpp=enabled -Drga=disabled
脚本在安装插件前检查 ELF;如果插件仍直接依赖 librga,构建立即失败。
(四)保持解码器侧 NV12 隔离
网页流启用时,解码器到 tee 的入口固定为:
capsfilter caps=video/x-raw,format=NV12
! identity drop-allocation=true
! tee name=stream_video_tee
该处理避免 WebRTC 分支反向影响硬件解码器的输出格式和 allocation 协商。
(五)原子部署
scripts/upload.sh 先将播放器、插件和启动脚本上传为 /tmp/*.new, 全部成功后再用 mv 替换正式文件,并删除 GStreamer registry:
rm -f /root/Test/gst-test/cache/registry.bin
这样可以避免网络中断时留下半写入的可执行文件或共享库。
九、性能与功能影响
| 模块 | 修复后行为 | 影响 |
|---|---|---|
| 视频解码 | 继续使用 mppvideodec 硬件解码。 | 硬件解码能力保留。 |
| 物理 HDMI | 继续使用 NV12 和 kmssink。 | 输出格式和画面质量不变。 |
| 网页流编码 | 继续使用 mpph264enc 硬件编码。 | H.264 编码仍由硬件完成。 |
| 视频格式转换/缩放 | 使用 GStreamer CPU 路径,不再调用 RGA。 | 会增加一定 CPU 使用率,应在双路 1080p 网页流压力测试中持续观察。 |
| 音频 | HDMI ALSA、DEP 和 WebRTC Opus 路径不受此次修复直接影响。 | 功能保持不变。 |
此修复不是将整个播放器改成软件解码或软件编码。只有原始视频的颜色格式转换和缩放改为 CPU 路径。
当前真实验证记录没有给出统一的 CPU 百分比,因此本文不虚构“1080p 增加 xx%”之类的数字。对 1080p 实时流,建议记录单路和双路 WebRTC 的 CPU 峰值与平均值;4K 场景则应单独进行压力测试,确认 CPU 转换是否满足帧率和温度要求。
十、构建与验证
(一)交叉编译
cd /home/cuijc/xiangmu/RK3588-GStreamer-Player
bash scripts/build.sh
scripts/build.sh 先构建无 RGA 的 Rockchip MPP 插件,再交叉编译播放器。
(二)部署
bash scripts/upload.sh
(三)核对文件哈希
开发机:
sha256sum build-rk3588/rk3588_gst_player \
third_party/rk3588-sdk/target/usr/lib/gstreamer-1.0/libgstrockchipmpp.so \
scripts/use-gst-test.sh
板端:
sha256sum /root/Test/gst-test/app/rk3588_gst_player \
/root/Test/gst-test/lib/gstreamer-1.0/libgstrockchipmpp.so \
/root/Test/gst-test/use-gst-test.sh
最终部署时应确认三项本地与板端哈希完全一致;本文记录的具体 SHA-256 放在附录 C,正文只保留核对方法。
(四)验证运行环境
/root/Test/gst-test/use-gst-test.sh env | \
grep -E "GST_(VIDEO_CONVERT_USE_RGA|MPP_NO_RGA)="
预期:
GST_MPP_NO_RGA=1
GST_VIDEO_CONVERT_USE_RGA=0
(五)验证 MPP 插件
/root/Test/gst-test/use-gst-test.sh gst-inspect-1.0 mppvideodec
strings /root/Test/gst-test/lib/gstreamer-1.0/libgstrockchipmpp.so | \
grep "RGA disabled at compile time"
gst-inspect 中的插件路径应为:
/root/Test/gst-test/lib/gstreamer-1.0/libgstrockchipmpp.so
(六)最终运行验证
用户按原流程启动播放器,在 HDMI 已经显示目标素材后发送 streamControl。验证结果:
网页实时流能够成功生成;物理 HDMI 继续播放;日志中不再出现 RgaBlit、RGA_BLIT fail 或 Segmentation fault; rk3588_gst_player 不再崩溃。
十一、建议复测方法
- 重启板子,确保清除上一次 RGA 内存破坏造成的系统异常。
- 使用标准脚本启动播放器:
/root/Test/gst-test/use-gst-test.sh \ /root/Test/gst-test/app/rk3588_gst_player - 确认启动日志出现:
[GStreamer] CPU video conversion forced; libgstvideo RGA disabled - 等待 HDMI 显示目标素材。
- 发送
streamControl。 - 打开接口返回的
streamUrl,确认网页有视频和音频。 - 至少持续播放 10 分钟,观察 HDMI、网页流、DEP 音频和进程稳定性。
- 检查日志中不存在:
RgaBlit RGA_BLIT fail Segmentation fault corrupted size - 使用
top记录单路和双路网页流下的 CPU 使用率。
十二、排障经验总结
- 看到 RGA 日志不能直接认定调用者是 MPP 插件;RGA 可能由 GStreamer 核心视频库间接调用。
gst-inspect的实际插件路径和 SHA-256 核对,是排除旧文件部署问题的必要步骤。readelf -d用于区分直接依赖,ldd会同时显示间接依赖,不能混为一谈。nm -D和源码全文搜索可以从二进制符号追溯到真正调用点。- 第一次修复未解决问题并不是插件未上传,而是只关闭了错误层级的 RGA 开关。
- 对会造成内存破坏的硬件加速路径,应在应用和启动环境两层关闭,不能只依赖外部 shell 配置。
- 媒体 pipeline 测试一旦出现 RGA 内存破坏,应先重启板子,再继续部署或验证,避免把系统异常误判为新代码问题。
经验总结:
- WebRTC 新增的不只是网络发送,还可能改变视频处理链路。
- HDMI 正常并不代表 WebRTC 的格式转换和编码路径正常。
- 看到 RGA 错误,不要默认认为是 MPP 在调用 RGA。
- 应结合日志、符号、动态依赖和源码搜索,定位真正的调用者。
- 硬件加速出现稳定性问题时,优先关闭单一路径,而不是放弃全部硬件能力。
火山引擎视频云技术社区,是面向 AI 音视频开发者的技术交流平台。这里汇聚源自抖音、豆包等亿级 DAU 产品的 RTC、直播、点播、AI 媒体处理、音视频互动技术,提供接入指南、最佳实践、性能调优、场景案例、Demo 代码、开源项目、白皮书和 API 文档。社区汇聚官方工程师与一线开发者,为 AI 视频通话、数字人、AI 视频处理等应用的开发与落地提供技术支持。
更多推荐
所有评论(0)