ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

RK3588 WebRTC 实时流卡顿优化:从视频桥接到 H.264 PTS 回退

RK3588 WebRTC 实时流卡顿优化:从视频桥接到 H.264 PTS 回退 总结这次卡顿不是单纯的网络丢包或编码帧率不足而是先由跨 pipeline 视频桥接和缩放增加了处理负担后又暴露出 H.264 B 帧导致的非单调 PTS最终通过 appsink/appsrc 直连、限制 videorate 补帧并让不满足 PTS 条件的素材回退到 MPP 硬件编码恢复了 WebRTC 的稳定呈现。一、背景RK3588 实时流为什么会卡顿我们在RK3588上开发了一个音视频播放器该播放器同时做两件事一条路径把素材解码后送到 HDMI另一条路径把视频和音频编码为 WebRTC 流交给浏览器播放。两条路径共享解码输入但对格式、时间戳、编码和调度的要求不同因此“HDMI 看起来正常”并不等于“网页实时流正常”。视频文件 / 采集输入 | v MPP 硬件解码把压缩视频变成 NV12 原始帧 | -------------------- | | v v HDMI / kmssink WebRTC 视频路径 | -- H.264 编码 -- RTP -- 浏览器 解码音频 -- HDMI/DEP 输出 | -- PCM -- Opus 编码 -- RTP -- 浏览器本文中的rk3588_gst_player是运行在板端的 GStreamer 播放器进程MPP 是 Rockchip 的硬件媒体处理框架负责硬件解码和 H.264 编码。WebRTC 不是“把 HDMI 画面直接发出去”它还要求稳定的 RTP 时间线、浏览器可处理的编码格式和可预测的呈现时间戳。一需要知道的几个术语术语本文中的含义appsink/appsrcGStreamer 用于把一个 pipeline 的样本取出再送入另一个 pipeline 的接口本文用它替代跨 pipeline 的 inter sink。RTP承载 WebRTC 音视频的实时传输包一帧 H.264 可能拆成多个 RTP 分片。PTS / DTSPTS 是应该显示的时间DTS 是解码顺序时间B 帧可能让 PTS 暂时回退而 DTS 仍递增。jitter buffer浏览器为吸收网络和时间戳抖动而设置的缓冲区时间线异常会让它变大并增加延迟。B 帧依赖前后参考帧进行显示重排的帧类型压缩效率较高但直通 WebRTC 时必须检查 PTS 是否仍然单调。H.264 直通不重新解码再编码而是把素材中已压缩的 H.264 帧直接送入 WebRTC它省掉编码成本但也把源时间戳问题带进了实时流。ZLMediaKit 是板端媒体服务器编码后的 RTP 由实时流管理器共享给它再由它分发给浏览器因此本文重点分析的是“播放器产生什么样的帧和时间线”不是公网端口或浏览器页面本身。本文记录对 RK3588 GStreamer Player 网页实时流卡顿问题的完整排查和优化过程包括最初现象和假设为板端和浏览器补充的诊断指标每一轮 pipeline 和配置调整H.264 直通引入 B 帧时间戳问题的原因最终自动混合策略及验证数据后续更换素材或继续优化时的回归方法。本文只讨论“物理 HDMI 播放正常或相对流畅但开启网页实时流后 HDMI 或网页出现卡顿”的问题。项目早期 4K60 双通道播放能力问题不在本文范围内。二优化过程路线这次排查不是一次性找到 PTS而是沿着“先确认性能再确认时间线”的路线逐步收敛阶段 1发现 WebRTC 开启后卡顿 | v 阶段 2发现跨 pipeline 桥接增加了额外负担 | v 阶段 3用 appsink/appsrc 替代 intervideosink/intervideosrc | v 阶段 4尝试 H.264 直通降低编码压力 | v 阶段 5发现 B 帧 PTS 重排导致 WebRTC 延迟和呈现卡顿 | v 阶段 6根据 PTS/DTS 自动判断直通资格不合格时回退硬件编码后文每一轮优化都回答一个具体问题瓶颈到底在板端处理量、桥接时间线、网络传输还是源视频的显示时间戳。二、最终结论实时流卡顿不是由单一环节造成而是先后包含三个问题固定输出为 1920x1080 时将约 1280x718 的素材放大增加了板端缩放、编码、网络和浏览器解码负担。早期intervideosink/intervideosrc videorate桥接会重复 surface 或产生 GAP buffer开启实时流后可能同时影响 HDMI 和网页流的节奏。后期 H.264 直通虽然消除了缩放和重新编码但含 B 帧的点播素材存在非单调 PTS。该时间戳进入 WebRTC 后显著增大 jitter buffer并导致 Chrome 丢帧和呈现卡顿。最终方案由以下部分组成使用appsink/appsrc直接桥接解码后的视频和 PCM 音频videorate设置 200 ms 最大补帧间隔避免长时间停播后生成大量 GAP 帧支持fixed和source两种分辨率模式使用共享 RTP一路通道只处理/编码一次多个浏览器复用结果source模式使用自动混合视频策略H.264 先验证首个 GOP只有 PTS 单调的素材才允许直通检测到 PTS 回退且 DTS 单调时将当前素材锁定到 MPP H.264 硬件编码音频始终由 PCM 编码为 Opus不执行音频直通。最终测试中浏览器丢帧由 57 降为 0freeze 由 1 降为 0实际呈现帧率由约 25.75 fps 恢复到约 30.04 fps。三、初始现象与第一轮判断最初观察到只播放 HDMI 时相对流畅开启实时流后网页播放比 HDMI 卡部分测试中开启实时流后物理 HDMI 也比未开启时卡板端硬件编码约 29.9 fps最大输入帧间隔约 33 ms说明最初不能只把问题归因于 MPP 编码不稳定。当时使用的网页流接近 1920x1080、30 fps而素材约为 1280x718、29.97 fps。初步风险包括videoscale将非标准 720p 素材放大到 1080p固定 30 fps 与素材原始帧率或 HDMI 显示刷新率不完全一致WebRTC 网络 jitter、浏览器 jitter buffer 和 VSync 合成可能丢帧浏览器显示的“解码 fps”不等于用户真正看到的“呈现 fps”。第一轮采用低风险配置将网页流降到 720p30[stream] video_resolution_mode fixed video_width 1280 video_height 720 video_fps 30 video_bitrate 2500000该调整降低了缩放、网络传输和浏览器解码压力但只能缓解问题不能解释所有偶发卡顿。videoscale负责改变画面尺寸VSync是显示器刷新与浏览器合成节奏。它们会影响最终“看到的帧率”但不能替代板端 RTP 和浏览器呈现指标。四、先建立可观测性排查过程中没有直接缩短 RTP 队列。原因是 H.264 一个图像可能拆成多个 RTP 分片盲目缩短或丢弃队列中的单个 buffer 可能破坏一帧反而增加花屏和卡顿。一网页 CSV 指标内置播放器增加了每 2 秒采样的 CSV 日志主要字段包括字段含义decoded_fpsChrome 解码帧率frames_dropped/dropped_delta浏览器累计/本窗口丢帧jitter_msWebRTC 入站 RTP jitterpackets_received/packets_lost视频 RTP 收包和丢包freeze_count浏览器检测到的累计冻结次数presented_fpsrequestVideoFrameCallback统计的实际呈现帧率max_present_gap_ms当前窗口最大呈现帧间隔long_present_gap_count当前窗口超过 50 ms 的呈现间隔次数visibility_state页面是visible还是hiddendecoder_implementation浏览器上报的解码器实现部分 Chrome 版本为空power_efficient_decoder浏览器是否报告高能效解码器部分版本为空jitter_buffer_avg_delay_ms浏览器累计 jitter buffer 平均延迟CSV 最多保留约 12 小时刷新页面后清空。分析时必须排除visibility_statehidden的窗口因为后台标签页会暂停或降低视频呈现频率。二板端 5 秒统计板端为共享实时流 pipeline 增加了每 5 秒汇总Encoder cadenceRTP 视频输出 fps 和最大帧间隔Audio RTPOpus RTP 包数和字节数Audio bridge inputPCM 输入数量、字节数和时长Video modeh264-passthrough或hardware-encodeVideo stageappsrc_out、videorate_out、videoscale_out、encoder_out四阶段帧率和间隔Video rate/queuevideorate输入、输出、丢弃、复制以及 queue 深度和溢出次数。这些数据用于区分板端输入或编码不稳 ↓ RTP/network jitter 或丢包 ↓ Chrome 解码不足 ↓ 浏览器合成/VSync 呈现不稳仅看网页底部瞬时 fps 不足以判断问题因为短窗口、抖动补偿和页面可见性都会使数值波动。五、替换实时流桥接链路早期重点检查的链路是intervideosrc - videorate - videoscale - mpph264encintervideosink/intervideosrc按独立周期传递 surface停流、恢复或上下游时钟不一致时可能重复旧 surface并产生 GAP buffer。开启实时流后该行为会让videorate继续补帧增加额外调度和时间线扰动。这里的 GAP buffer 可以理解为“时间线上有位置、但没有真实视频内容的占位帧”如果下游继续追赶时间线短暂停流可能被放大成大量补帧。最终改为HDMI playbin 解码输出 | - kmssink物理 HDMI | - appsink - appsrc - WebRTC 共享处理链音频也改为 PCMappsink/appsrc桥接不再依赖interaudiosink/interaudiosrc。每个 buffer 只转交一次实时流开关通过常驻分支中的 valve 控制不需要重建 HDMI 播放 pipeline。这轮修改后物理 HDMI 和网页流的主观流畅度都明显改善。六、限制 videorate 长时间补帧硬件编码回退链中的videorate使用skip-to-firsttrue max-duplication-time200000000即最大补帧间隔为 200 ms。正常的 29.97 fps 到 30 fps 调整远小于该值不受影响当素材停止很久后恢复时不会为中断期间生成大量 GAP 帧追赶时间线。对应实现位于app/WebRtcStreamManager.cpp的StartEncoder()。“实时流持续开启、素材停止数小时后恢复”仍属于需要单独长时间验证的场景不能仅凭短时测试认定完全覆盖。七、fixed/source 两种分辨率模式为避免要求节目单中的所有素材都使用同一分辨率增加了两种配置模式。fixed表示先把所有素材转换到统一输出规格source表示尽量保留素材的源分辨率再由浏览器按页面尺寸显示。一fixedvideo_resolution_mode fixed video_width 1280 video_height 720 video_fps 30 video_bitrate 2500000行为始终经过videorate ! videoscale ! mpph264enc输出严格遵循配置宽高、帧率和码率不启用源 H.264 直通适合必须统一网页流规格的场景。二sourcevideo_resolution_mode source video_fps 30 video_bitrate 2500000行为video_width和video_height被忽略两个 HDMI 通道分别按各自素材分辨率工作浏览器负责把视频按页面尺寸显示无法直通时仍使用 MPP H.264 编码但不强制缩放到固定宽高4K 等高分辨率仍需确认浏览器解码能力和网络带宽。物理 HDMI 和网页流是不同输出路径。HDMI 可由 DRM/KMS plane 适配显示器模式网页流是否缩放由[stream].video_resolution_mode决定。阶段小结fixed更容易控制输出规格但会付出缩放成本source减少不必要的缩放却要求后续的 H.264 直通资格判断更加严格。八、第一版自动混合模式H.264 直通看起来非常有吸引力因为它可以跳过重新编码减少 CPU 占用和端到端延迟但代价是播放器必须承担源 H.264 时间戳质量的风险。为了进一步降低开启实时流后的开销source模式增加了两个视频分支硬件编码分支 NV12 appsrc - videorate - videoscale - mpph264enc - h264parse -- | - input-selector | - rtph264pay H.264 直通分支 | - 共享视频 RTP 源 h264parse probe - H.264 appsrc - h264parse ------------------音频链保持PCM appsrc - audioconvert - audioresample - opusenc - rtpopuspay第一版判断 Baseline、Constrained Baseline、Main 和 High Profile 为浏览器可接受的 H.264并在关键帧切换到直通。H.265、其他编码和不兼容 Profile 自动使用 MPP 编码。测试曾确认直通工作Video mode: h264-passthrough passthroughInputFrames: 约 150 帧/5秒 appsrc_out: 0 videorate_out: 0 videoscale_out: 0 encoder_out: 0这证明直通期间mpph264enc没有接收视频帧网页实时流不再额外执行缩放和视频编码。HDMI 播放本身仍需要解码音频仍需要 Opus 编码。阶段小结H.264 直通确实降低了板端处理量但“能直通”只说明编码格式可接受还没有证明 RTP 时间戳适合 WebRTC。转折提示到这里问题已经从“性能不足”转变为“时间线不适合实时传输”。前面的桥接优化解决了额外处理负担但不能保证点播 H.264 的 PTS 适合 WebRTC 直通。九、直通后仍卡顿发现 B 帧问题第一版 H.264 直通后板端输入和 RTP 输出仍接近 30 fps但网页 CSV 显示Chrome 解码接近 30 fps实际呈现显著低于 30 fpsRTP 没有网络丢包jitter 和 jitter buffer 延迟明显升高浏览器出现累计丢帧和 freeze。问题不在“Chrome 是否支持 High Profile”而在“该压缩码流是否适合低延迟 WebRTC 直通”。对测试素材执行ffprobe -v error -select_streams v:0 \ -show_entries streamcodec_name,profile,level,width,height,has_b_frames,r_frame_rate,avg_frame_rate,bit_rate \ -of defaultnoprint_wrappers1 \ /mnt/udisk/materials/复仇者联盟4-单音轨.mp4关键结果codec_nameh264 profileHigh width1280 height718 has_b_frames1 level31 avg_frame_rate30000/1001 bit_rate1501271再检查压缩包时间戳ffprobe -v error -select_streams v:0 -read_intervals %#30 \ -show_entries packetpts_time,dts_time,flags -of csvp0 \ /mnt/udisk/materials/复仇者联盟4-单音轨.mp4前几帧呈现为PTS: 33 - 100 - 67 - 167 - 133 - 234 - 200 ms DTS: 0 - 33 - 67 - 100 - 133 - 167 - 200 msDTS 按解码顺序单调递增但 PTS 因 B 帧显示重排持续前跳和回退。板端直通统计中的最大正向时间戳间隔因此反复达到 100 ms而正常 29.97 fps 相邻显示帧间隔应约为 33.4 ms。Chrome 虽然能够解码这些帧但 WebRTC jitter buffer 需要吸收非单调显示时间戳最终表现为缓冲延迟增大、呈现帧率下降和间歇丢帧。更换开源网页播放器不能消除源 RTP 时间戳问题。这并不意味着 WebRTC 协议禁止 B 帧这里的结论只针对本案例的低延迟直通链路当源 PTS 频繁重排时重新编码成单调时间线比直接复用点播码流更稳妥。定位结论这一轮数据把问题从“网络是否丢包”进一步缩小到“源 H.264 的显示时间线是否适合实时直通”。十、最终自动混合策略最终策略不再只检查 H.264 Profile而是加入运行时 PTS 资格判断。一新素材开始默认选择硬件编码分支记录压缩 H.264 的 PTS 和 DTS在硬件编码继续输出的同时观察首个完整 GOP首个 GOP 内 PTS 始终单调时才在下一个关键帧切换直通。二 B 帧判定同时满足以下条件时判定存在呈现重排当前 PTS 上一个 PTS DTS 没有回退 当前 buffer 没有 DISCONT caps 没有切换这样可把 B 帧重排与 seek、素材切换或时间线重置区分开。一旦检测到 B 帧重排当前素材锁定为hardware-encode后续即使遇到关键帧也不再尝试直通只有NotifyVideoSourceReset()收到真实素材切换事件后才清除锁定并重新判断。板端会打印H.264 passthrough disabled for current source: PTS rollback ... with monotonic DTS (B-frame reordering detected) Video mode: hardware-encode (H.264 PTS reordering blocked passthrough)资格判断和状态切换位于app/WebRtcStreamManager.cpp的PushEncodedVideoSample()压缩 H.264 probe 位于app/CGStreamerPlayer.cpp通道转发位于app/ChannelPlayer.cpp。十一、最终数据对比对比日志B 帧 H.264 直通rk3588-webrtc-channel-1-20260807133047103.csv增加 PTS 回退保护后rk3588-webrtc-channel-1-20260807140256820.csv统计均排除连接初始阶段最终日志还排除了visibility_statehidden的三个后台标签页窗口。指标B 帧 H.264 直通PTS 检测后 MPP 回退Chrome 解码 fps29.6030.03页面可见时实际呈现 fps25.7530.04jitter55.9 ms1.4 msjitter buffer 平均延迟151.9 ms12.4 ms最大呈现帧间隔200.1 ms66.7 ms每 2 秒长呈现间隔次数14.91.8浏览器累计丢帧570freeze10视频 RTP 丢包00音频 RTP 丢包00板端最终稳定统计Video mode: hardware-encode (H.264 PTS reordering blocked passthrough) Encoder cadence: 约 30 fps maxFrameGapMs: 33 encoder_out: 约 150 帧/5秒 queueOverruns: 0 Audio RTP: 约 250 包/5秒这组数据说明MPP 编码输出时间戳恢复为单调的约 33 ms 间隔jitter buffer 平均延迟降低约 92%浏览器解码和实际呈现都恢复到约 30 fps主观改善与板端、RTP 和浏览器三层数据一致。十二、快照下的推荐配置素材分辨率不统一、希望避免不必要缩放时[stream] max_viewers_per_channel 4 video_resolution_mode source video_width 1280 video_height 720 video_fps 30 video_bitrate 2500000 hdmi1_av_delay_ms 0 hdmi2_av_delay_ms 0在source模式下video_width和video_height不参与网页流处理保留这两个值是为了以后切回fixed时有明确配置。如果业务要求所有网页流严格统一为 1280x720、30 fps则使用video_resolution_mode fixed video_width 1280 video_height 720 video_fps 30 video_bitrate 2500000十三、回归测试方法一构建和部署在 Ubuntu 开发机执行bash scripts/build.sh bash scripts/upload.sh板端启动/root/Test/gst-test/use-gst-test.sh \ /root/Test/gst-test/app/rk3588_gst_player二含 B 帧 H.264预期日志H.264 passthrough disabled ... PTS rollback Video mode: hardware-encode (H.264 PTS reordering blocked passthrough) encoder_out: 约目标 fps maxFrameGapMs: 接近单帧间隔不应在后续关键帧重新切回直通。三无 B 帧且 PTS 单调的 H.264预期日志H.264 passthrough qualification started Video mode switched to H.264 passthrough Video stage encoder_out: frames0需要使用已确认has_b_frames0的素材完成板端回归。四H.265 或其他编码预期始终为Video mode: hardware-encode encoder_out: 约目标 fps五浏览器 CSV测试时保持页面可见并至少采集 2 分钟。重点检查decoded_fps和presented_fps是否接近目标帧率frames_dropped是否持续增长freeze_count是否增长jitter_ms是否长期偏高jitter_buffer_avg_delay_ms是否持续升高packets_lost是否增长max_present_gap_ms是否反复达到 100 ms 以上。六仍需覆盖的场景实时流持续开启、素材停止数小时后恢复H.264 无 B 帧素材完成首 GOP 验证并切换直通H.264/H.265/不同分辨率素材连续切换两个 HDMI 同时使用不同分辨率和不同编码多浏览器同时连接同一通道浏览器开启声音后的长时间音视频连续性fixed与source重启切换页面后台再回到前台后的统计恢复。十四、经验总结编码 fps 稳定不代表网页实际呈现稳定必须同时采集浏览器呈现数据。packets_lost0不代表没有 RTP 时序问题非单调 PTS 同样会放大 jitter buffer。浏览器支持某个 H.264 Profile不等于该码流适合低延迟 WebRTC 直通。点播 H.264 常使用 B 帧提高压缩效率而在低延迟 WebRTC 场景中无 B 帧、单调 PTS 的编码输出通常更容易获得稳定表现。RTP 队列不是第一个应该调整的参数。先定位丢帧发生在板端、网络、解码还是呈现阶段。自动直通必须有可回退条件并且回退结果需要按素材锁定避免模式反复切换。页面不可见时的presented_fps0是浏览器正常节流分析 CSV 时必须结合visibility_state。优化最终必须由主观观察和板端、RTP、浏览器三层数据共同验证。
返回列表