ARTICLE DETAIL

资讯详情

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

桌面共享双协议推流:RTSP与RTMP服务搭建与优化

桌面共享双协议推流:RTSP与RTMP服务搭建与优化 简介一套基于C的桌面共享与音视频推流实现方案针对Windows环境完成屏幕和声卡数据采集并对接RTSP本地转发、RTSP推流和RTMP推流三种输出链路。项目完整覆盖屏幕采集DXGI/GDI、音频采集WASAPI、H.264/AAC编码同时支持NVIDIA NVENC独显硬件编码与Intel QSV核显硬件编码配有SDL2/ImGui实现的简单操作界面可应用于远程桌面、直播推流、课程录播等场景的开发者学习和二次开发。压缩包约21.03MB页面暂无文件总数与类型明细内容以C工程源码、模块配置和编译说明为主。已有1689人浏览学习适合具备一定C与网络基础、希望系统掌握音视频采集、编码及RTSP/RTMP推流全过程的读者参考。项目从屏幕抓取到推流输出形成完整闭环代码模块划分清晰学习时能直观理解实时音视频传输链路也便于在此基础上扩展自定义推流策略。 桌面共享是个老话题但真要把它做成一个能对外提供RTSP和RTMP输出的服务事就没那么简单了。最近我完整做了一个DesktopSharing的项目本机桌面实时采集后编码成H.264再分别通过RTSP和RTMP两条链路推出去局域网里用VLC直接拉流公网里通过直播服务器转播整个过程踩了不少坑。如果你也准备做类似的桌面共享方案或者正在纠结面对不同设备时到底该用RTSP转发还是RTMP推流、怎么选型怎么搭服务这篇文章应该能帮你省不少时间。我要把背景交代清楚这个DesktopSharing项目不是要做远程控制软件它更像是一个桌面画面发布器把当前屏幕内容变成一路可被任意播放器消费的实时流同时兼顾局域网和公网两类传输场景。因此协议栈、采集方式、编码参数、服务器选型这些细节都会直接影响最终的画质和延迟表现值得逐一拆开说。1. 项目背景与方案选型为什么同时押注RTSP和RTMP1.1 桌面共享的典型应用场景我这边收到的诉求大概分三类。一是教学或会议演示讲师屏幕要同步投到会议室大屏和线上课堂延迟要低画面要清晰二是无人值守场景的可视化比如机房服务器操作界面需要实时回传到监控中心方便远程确认状态三是直播场景软件操作教程或者游戏画面推到B站、视频号这类公网平台供大量观众在线观看。这三种场景的传输通道差异很大。本地教学演示基本走局域网延迟低于300毫秒体验才合格机房回传可能还要穿过跨地域专线公网直播则必须依赖CDN和标准直播协议。如果只支持一种协议就必然会有一类场景用不了。所以我的技术选型从一开始就确定RTSP和RTMP都要支持一个管低延迟可控播放一个管公网分发。另外桌面视频源和摄像头视频源有一个关键差异画面的内容变化率极度不均匀。静止状态下桌面可能几分钟都不怎么变化一旦开始操作又是满屏刷新。这种特性对编码策略的考验很大后面我会专门讲GOP和码率控制怎么配。1.2 RTSP与RTMP的定位差异先纠个常见误解。RTSP本身并不负责传输媒体数据它更像是一个会话遥控器负责协商流格式、建立会话、控制播放暂停等真正的音视频数据通过RTP包在UDP或TCP上传送。因为控制能力完整RTSP很适合监控、安防、实时交互这种场景。RTMP则是Adobe推出的直播协议基于TCP长连接把音视频数据封装成FLV tag流式传输。它几乎没有seek、暂停这类控制逻辑强项是穿透性好、CDN分发生态极其成熟。要做公网直播RTMP几乎是必经之路。我用生活里的交通方式来类比RTSP像自己开车路线灵活、想停就停适合局域网这种熟人路网RTMP像坐高铁线路固定但运力强、跑得远适合跨地域的长途运输。两者不是替代关系而是互补关系。维度RTSPRTMP传输层主要走RTP/UDP也可RTP/TCPTCP长连接控制能力支持播放/暂停/seek弱专注直播延迟表现可做到200ms级别常规1~3秒生态现状安防设备、低延迟场景Web直播、CDN分发适合场景局域网拉流、视频监控公网直播、跨网分发1.3 为什么用GStreamer而不是纯FFmpeg桌面采集、编码、协议封装这一整套用FFmpeg命令行也能实现比如x11grab采集后直接推RTSP。但遇到动态控制、并发处理多路流或者需要把一路桌面流同时输出给本地RTSP服务和远端RTMP服务器时FFmpeg命令行的短板就很明显了。我最终选了GStreamer作为实时流处理框架核心原因有两个。一是它在Ubuntu 24.04和Windows上都有成熟支持采集、编码、RTP封包、RTSP服务端都有现成插件二是GStreamer的pipeline模型天然适合一路源、多路输出的拓扑编码器的输出通过tee插件可以分叉成多条路互不阻塞。对桌面共享这种要同时支持RTSP转发、RTSP推流、RTMP推流的项目来说这种灵活性非常关键。不过GStreamer对RTMP推流的支持不像RTSP那么原生需要额外插件或做一次FLV桥接这部分实操细节放到第3节详细说。2. 核心链路拆解从桌面像素到网络流2.1 桌面采集三个平台三种脾气桌面采集是整个链路的第一环也是最容易翻车的一环。Windows上最稳的方案是DXGI Desktop Duplication可以高效抓取桌面帧缓冲还能感知画面变化区域属于性能开销最小的方案。Linux这边就比较分裂了X11环境下用x11grab或者在GStreamer里用ximagesrc都能采集但Ubuntu 24.04默认登录会话已经切到Wayland在Wayland下用X11采集只能拿到一张静态壁纸这个坑我浪费了一整个下午才排查出来。Wayland环境下的正道是用GNOME自带的ScreenCast接口通过xdg-desktop-portal唤起系统的屏幕共享授权用户点允许之后才能拿到视频流。这样确实多了交互成本但权限管理更规范也符合最新桌面系统的安全方向。采集环节还有个容易忽略的追求帧率稳定性。桌面静止时CPU占用必须压低。我一般开启帧率自适应策略内容变化时按目标帧率输出静止时自动降帧甚至不输出新帧。这一步能大幅降低后续编码和网络传输的压力尤其适合长时间运维演示的场景。2.2 编码器选型软编还是硬编编码器决定了画质、码率和延迟的上限。我实测对比了x264软编和NVENC硬编两种路线。结论是实时桌面共享优先用硬编。因为桌面分辨率通常不低于1080p高帧率下x264的CPU占用非常可观跑在办公机上很容易把前端交互拖卡。x264也不是不能用关键是参数要对齐场景。实时交互场景下编码器预设用ultrafast或veryfast加上tunezerolatency把B帧和延迟缓冲关掉GOP设成1秒一个关键帧30帧率就设keyint30码率控制用CBR尽量让码率平稳。硬编这边的NVENC同样有low-latency预设思路是一致的。这里有一个桌面场景特有的细节屏幕上文字和UI元素多黑白对比度高码率给低了会在文字边缘出现振铃和噪点。我的经验是1080p桌面共享码率起点放在4~5Mbps网络不好的时候再动态降到2Mbps再低就明显发虚了。2.3 一路源、多路输出的架构设计因为要同时支持RTSP转发、RTSP推流和RTMP推流最理想的设计是采集编码只做一次然后复制编码后的裸流分别走不同协议出口。这样CPU开销最小各条链路也不会互相阻塞。实现上GStreamer的tee插件就是干这个的。编码器输出裸H.264流之后分出一路去本地RTSP服务器对外提供拉流服务另一路封装成FLV tag走RTMP推流。两条链路共用同一个源任何一个播放端的退出都不会影响另一路。需要单独说明的是RTSP转发这个功能。项目里有种常见使用场景本机或局域网内有一台摄像头已经提供了RTSP流但多个客户端同时去拉流会把摄像头搞挂。DesktopSharing增加了代理模式先把摄像头RTSP流拉到本地再通过本地RTSP服务重新分发出去。摄像头侧只承受一路连接分发能力完全由本地RTSP服务器的带宽决定。这个功能听起来不起眼实际在安防对接项目中帮了大忙。3. 实操在Ubuntu 24.04搭建RTSP/RTMP推流服务3.1 环境准备与依赖安装我建议的基础环境是Ubuntu 24.04 LTS桌面会话优先Xorg如果只能用Wayland采集环节要多做一步屏幕授权处理。先把依赖装好sudo apt update sudo apt install -y ffmpeg gstreamer1.0-tools gstreamer1.0-plugins-base \ gstreamer1.0-plugins-good gstreamer1.0-plugins-bad \ gstreamer1.0-plugins-ugly gstreamer1.0-libav libx264-devUbuntu 24.04源里的GStreamer版本是1.24比22.04多了些新插件部分rtmp2sink、RTSP服务端插件分布在plugins-bad中装完一般就能找到。RTMP服务器我选了SRS全称Simple Realtime Server。它配置比Nginx-RTMP简单性能也更好而且是一个单二进制文件下载编译就能跑wget https://github.com/ossrs/srs/archive/refs/tags/v6.0.120.tar.gz tar zxvf srs-6.0.120.tar.gz cd srs-6.0.120/trunk ./configure --full make -j$(nproc)开发阶段用SRS默认配置就能撑住测试需求监听1935端口RTMP推流地址就是rtmp://服务器IP:1935/live/你的流名。3.2 RTSP推流与转发实现先用GStreamer命令行验证桌面采集加编码推流是否正常。X11环境下gst-launch-1.0 -v ximagesrc use-damagefalse ! \ videoconvert ! video/x-raw,formatI420 ! \ x264enc tunezerolatency bitrate4000 speed-presetveryfast ! \ rtph264pay config-interval1 ! \ tcpserversink host0.0.0.0 port8554这条管线把桌面画面实时编码成H.264 RTP包推送到本机8554端口实际上就是一个简易的RTSP裸流供给端VLC或FFplay可以拉流验证ffplay -rtsp_transport tcp rtsp://127.0.0.1:8554/desktop命令行管线适合验证可行性真正要产品化落地我建议直接用GStreamer RTSP Server库来做服务端。通过Python的gi.repository.GstRtspServer接口可以注册一个名为desktop的媒体源推流和转发都能统一管理。RTSP转发那一路就在这个服务里加一个rtspsrc元素把远端摄像头的流拉进来解包后重新挂载到本地RTSP服务上。摄像头和播放端都认为自己在直连实际中间多了一层代理这就是转发的本质。3.3 RTMP推流实现RTP推流到RTMP服务器时我直接用FFmpeg最省事。X11桌面采集推SRS的命令ffmpeg -f x11grab -framerate 25 -video_size 1920x1080 -i :0.0 \ -c:v libx264 -preset veryfast -tune zerolatency -b:v 4M \ -pix_fmt yuv420p -flush_packets 1 \ -f flv rtmp://your-server-ip:1935/live/desktop这段命令的意思是把1920x1080的桌面以25帧率采集用libx264做实时编码以FLV格式推送到SRS。播放端VLC打开rtmp://your-server-ip:1935/live/desktop就能看到画面。如果要做的是RTSP转RTMP更聪明的做法是-c copy透传避免二次编码。FFmpeg可以直接从RTSP地址拉流然后封装成RTMP输出ffmpeg -rtsp_transport tcp -i rtsp://user:passip:554/Streaming/Channels/101 \ -c copy -f flv rtmp://your-server-ip:1935/live/camera这个命令把海康摄像头的RTSP主码流透传转成RTMP推流CPU占用极低因为没有任何解码和重新编码过程。Wayland会话下的桌面推流要绕一下x11grab在Wayland下失效需要通过PipeWire或者额外工具把屏幕输出映射成虚拟V4L2设备再让FFmpeg从V4L2源读取。我在项目里为了稳定起见直接安排桌面共享服务跑在Xorg会话下这算是当前阶段的实用主义选择。4. 常见问题排查与调试经验4.1 OpenCV打开RTMP失败的根因看到有人在网上问OpenCV打开RTMP失败这个问题我实际遇到过。OpenCV的VideoCapture::open在打开RTMP地址时依赖它内部编译的FFmpeg库但很多发行版打包的OpenCV默认不启用RTMP协议支持或者只支持RTSP拉流。最简单的排查方法是先单独验证FFmpeg能不能打开这个RTMP地址。如果FFmpeg能开再用OpenCV开还是失败那就说明是OpenCV自带FFmpeg的编译配置问题。解决方案有两个方向要么换一个带完整FFmpeg支持的OpenCV发行版要么绕开OpenCV的视频源层用FFmpeg拉流后把裸帧通过管道喂给OpenCV处理ffmpeg -i rtmp://server/live/stream -pix_fmt bgr24 -f rawvideo - | python3 process.py这个方法相当于把视频读取交给FFmpeg把图像处理留给OpenCV职责边界清晰也规避了OpenCV协议层支持不全的问题。4.2 桌面黑屏和花屏问题黑屏的常见原因有三个一是在Wayland会话里用了x11grab采集到的始终是静态壁纸或黑帧二是GNOME ScreenCast授权没被允许画面源根本没建立三是编码器参数不对比如没有关闭B帧导致延迟累积播放端前几秒一直是黑的。花屏则绝大多数是网络丢包。UDP传RTP时丢包会表现为大块绿色马赛克改走TCP传输-rtsp_transport tcp能立刻缓解。还有一个容易被忽视的小细节Wireshark抓包时如果没识别出RTSP协议需要手动执行Decode As选择RTSP不然会看到一堆裸RTP包排查效率很受影响。4.3 延迟优化实录我把延迟从最初的大约2秒优化到300毫秒一共做了这几件事首选就是编码器预设改ultrafast并开启zerolatency模式第二把GOP间隔改成与帧率一致也就是1秒一个关键帧减少播放端等待关键帧的时间第三RTSP播放端强制走TCP传输虽然流量更大但乱序等待少第四桌面共享默认不带声音的情况下把音频通道彻底移除省去音视频同步等待第五SRS的配置里把队列缓冲调小减少服务端的蓄水回合。延迟优化不能指望某一个参数一锤定音每个环节省几十毫秒叠加起来就是质的飞跃。桌面共享场景下超过1秒延迟就没法交互了所以这是必须较真的指标。4.4 摄像头RTSP地址兼容性接海康和小米摄像头时地址格式差异很大。海康一般是rtsp://用户名:密码IP:554/Streaming/Channels/101101是主码流102是子码流小米大多长这样rtsp://用户名:密码IP:554/ch0_0.h264。DesktopSharing的RTSP转发功能需要适配这类差异核心是对transport协商做兼容——有的设备只允许TCP拉流有的只能UDP有的需要先发OPTIONS探测能力。我在实现里做了一套回退逻辑优先尝试TCP握手失败自动回退UDP。这个逻辑一旦写好接入不同品牌摄像头的协调成本就降下来了。实际把这个项目从0到1跑通之后我最深的体会是桌面共享的技术难点不在某一个单点功能而在于把采集、编码、协议转换、分发、兼容性这些环节全部串成一条低延迟、高稳定的链路。RTSP和RTMP不是二选一的对立关系它们各自覆盖不同网络环境下的需求关键是要理解每个环节的延迟来自哪里、参数为什么要那么配而不是背几个命令就完事。这个项目后续其实还可以扩展WebRTC版本的实时端在公网场景下把延迟再降一个量级不过那是另外一个故事了。如果你正在做类似的事情我建议先把基础链路跑通再按我上面说的维度逐段优化不要一上来就追求极限参数不然你只会在配置文件和调试日志里迷失方向。本文还有配套的精品资源点击获取
返回列表