webrtc本身不推流,仅建立p2p连接;实现捕获+编码+推流需自主接管全链路或转封装rtp为rtmp,硬编码更稳低延,桌面捕获须注意分辨率16像素对齐与时间戳转换。

直接结论:WebRTC 本身不推流,它只建立点对点连接;要实现“捕获+H.264编码+推流”,必须绕过 WebRTC 的纯 P2P 模式,用 C++ 自主接管 capture → encode → RTMP/RTSP 封装 → socket 发送全链路,或把 WebRTC 输出的 RTP 流转封装为 RTMP。硬编码(NVENC/QSV)比 OpenH264 更稳、更低延迟、更省 CPU。
Windows 下用 libwebrtc 做桌面捕获,CreateDesktopCapturer 返回空怎么办
常见错误现象:CreateDesktopCapturer 返回 nullptr,日志里没报错但后续调用崩溃;或者捕获帧率极低(OnFrame 几乎不触发。
- 检查
DesktopCaptureOptions是否启用了 WGC(Windows Graphics Capture):Win10 1809+ 推荐开启,但需在编译时定义RTC_ENABLE_WIN_WGC,否则回退到 GDI+ 捕获,性能差且不支持多显示器缩放 - 确保调用线程是 UI 线程(Windows 要求 GDI/WGC 初始化必须在 STA 线程),libwebrtc 的
DesktopCapturer实例不能跨线程复用 - 若用
CroppingWindowCapturer或ScreenCapturerWinGdi,注意options.set_disable_dwm_chaining(true)必须设为true,否则 DWM 合成会导致黑屏或卡顿 - 捕获区域设置错误:传入的
DesktopRect若超出屏幕实际分辨率(比如多显示器拼接后总宽高算错),会静默失败
rtc_use_h264=true 编译后仍无法 H.264 编码,GetEncoder 返回空
这不是配置漏了,而是 WebRTC 的 H.264 编码器默认不启用硬件路径——OpenH264 是纯软编,仅用于兼容性兜底;真要低延迟,得手动绑定 NVENC/QSV。
- 确认编译参数含
--args="proprietary_codecs=true rtc_use_h264=true",且rtc_initialize_ffmpeg=true(解码用,非必需但建议开) - 运行时需显式注册硬件编码器:调用
webrtc::VideoEncoderFactory的子类(如NvencVideoEncoderFactory),并传给PeerConnectionFactoryInterface::CreatePeerConnection的encoder_factory参数 - OpenH264 默认不支持 B-frame 和 CABAC,编码质量差;若坚持用它,需在
VideoEncoderConfig中设number_of_simulcast_streams = 1,否则因 simulcast 不支持而 fallback 到 VP8 - 注意:WebRTC 的 H.264 encoder 输出的是 Annex-B 格式裸流(
00 00 00 01起始码),不是 MP4/FLV 容器,不能直接喂给 FFmpeg 的-i -
如何把 WebRTC 捕获+编码后的视频帧,转成 RTMP 推流
核心思路:不走 WebRTC 的 RTCPeerConnection 发送路径,而是从 VideoTrackSource 或 EncodedImageCallback 拿到 H.264 NALU,自己封装 SPS/PPS + 时间戳 + FLV tag,再用 TCP socket 发给 SRS/ZLMediaKit。
- 关键钩子点:重写
EncodedImageCallback::OnEncodedImage,从中提取encoded_image._buffer和encoded_image._length,注意每个 NALU 前需补全起始码(WebRTC 输出可能用 AVCC 格式,需转换) - SPS/PPS 必须在首帧前单独发送:从
OnEncodedImage的codec_specific_info中取codec_specific_info->codecSpecific.H264.packetization_mode判断是否为关键帧,并缓存首个 I 帧的 SPS/PPS(encoded_image.codec_specific_info里有) - 时间戳对齐:WebRTC 使用 90kHz 时钟,RTMP 要转成毫秒级
timestamp,公式为(rtp_timestamp % 90000) * 1000 / 90,否则播放端音画不同步 - 别直接用 FFmpeg 的
av_interleaved_write_frame:它依赖完整 AVFormatContext,而 WebRTC 输出无 PTS/DTS 序列,容易卡在av_write_frame阻塞;推荐用轻量级 RTMP 库(如librtmp或EasyRTMP)手动 push packet
为什么不用 WebRTC 直接推 RTMP,而要自己封装
因为 WebRTC 没有“推流”概念——它的 RTCPeerConnection 只发 RTP 包,目标是另一个 peer 的 UDP 端口。所谓“WebRTC 推流”,本质是信令服务器 + SFU(如 mediasoup)做中转,再由 SFU 把 RTP 转成 RTMP;但你若只要单向分发(比如远程看板),SFU 是冗余开销。
- WebRTC over UDP 在公网易被 QoS 限速或丢包,而 RTMP 走 TCP 更稳,适合弱网环境
- 浏览器端用
getDisplayMedia获取屏幕流后,JS 层无法访问原始 H.264 数据,只能走 MediaRecorder(输出 WebM/MP4,延迟高);C++ 后台才能拿到裸帧控制编码参数 - 硬编码器(NVENC)的
rc_lookahead、spatial_aq等参数 WebRTC 不暴露,但原生调用 NVENC SDK 可精细调节,这对桌面内容(文字/线条多)至关重要 - 真正工程落地时,
DesktopSharing这类项目已验证:DXGI 捕获 + NVENC 编码 + RTSP/RTP 封装,72 小时不掉流,延迟压到 120ms 内——它没碰 WebRTC 的信令和网络栈,只借用了其采集和编码抽象层
最易被忽略的一点:桌面捕获的分辨率对齐。NVENC 要求宽高均为 16 像素倍数,WebRTC 的 DesktopFrame 若未做 padding(比如 1920×1080 正好,但 1366×768 需 pad 到 1376×768),编码器会静默丢帧或输出花屏。这个 padding 必须在 DesktopCapturer::OnFrame 回调之后、送入编码器之前完成,不能依赖编码器自动处理。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











