打造内网低延迟直播系统
背景
因工作室的培训项目需要一个类似学校机房的内网直播系统,在我查阅了网络上的现成方案后发现了以下问题:
- 娱乐直播平台:需繁杂的实名认证,直播延迟过高,无法控制观看范围
- 腾讯会议,钉钉等直播:收费,直播清晰度较低,延迟较高
于是尝试自行搭建直播系统,目标
- 在局域网内流畅(20fps),低延迟(1s以内),高清晰度(1080p)
- 承载100人观看
- 便于自定义推流内容,例如某个程序,水印等
- 安全控制,杜绝未经授权的推流
- 录制流,便于后期观看
在查阅资料后找到了以下常用协议:
- rtmp:娱乐直播平台常见直播协议,便于分发,但延迟较高
- rtsp:网络摄像机常见直播协议,基于udp或tcp,延迟较低
- HLS:常用于播放各种节目,可回放,延迟很高
- webrtc:低延迟的直播协议,但是资料很少,配套推流设施不完善
本文使用rtsp方案
服务器的搭建
在查找了GitHub上的各种开源rtsp服务端之后,本人发现大部分服务器方案都比较简单,好在我们的使用情景不需要很多复杂功能,于是使用rtsp-simple-server
配置
该软件使用go编写,可以方便地在Linux和Windows平台上运行
1 | # supported stream protocols (the handshake is always performed with TCP). |
按照上面的配置文件进行配置即可
推流
推流使用的是OBS,因为OBS的推流选项无法直接推送rtsp流,所以使用录制功能完成推流
配置
路径
路径的填写方式是这样的
1 | rtsp://用户名:密码@服务器地址:端口/流id |
容器格式
我们使用rtsp协议推流,自然选择rtsp
视频比特率
由于我们直播的内容基本都是写代码,所以并不需要太高比特率,3000kbps足够(也许还能再小一些)
关键帧间隔
关键帧(i帧)是视频中图像的完整帧,后续帧(增量帧)仅包含已更改的信息。关键帧间隔增大可以节约网络带宽。
由于写代码场景背景几乎不变,预测帧能很好地工作,所以可以将间隔增大来节约带宽且不对画质产生较大影响
视频编码器
一开始我尝试了h264(h264和显卡编码),效果虽然还行但是并不是最佳的解决方案。考虑到客户端由我们进行分发,可以使用h265编码
我的显卡是10系显卡,可以使用显卡h265编码,所以选择(nvenc_hevc),一般来说显卡编码速度比CPU编码快
update: 使用显卡h264编码速度会更快一些(大概50ms左右),所以也可以使用显卡h264编码
视频编码器设置
1 |
|
-preset:v llhq
: 使用高质量低延迟预设(仅限显卡编码)
-tune:v zerolatency
: 使用低延迟模式
-profile veryfast
: 启用veryfast预设
图像大小和帧数
较低的帧数可以保证推流质量,在我们的应用场景中不需要过高的帧数,设置15-20即可
客户端
最容易找到的可方便自定义的客户端应该就是ffmpeg内自带的ffpaly了
1 | ffplay -fflags nobuffer -flags low_delay -analyzeduration 1000000 -i rtsp://xxxxx |
-fflags nobuffer
禁止缓存,减少播放时产生的延迟,但在网络较差的时候会导致丢包
-flags low_delay
低延迟模式
-analyzeduration 1
减少分析时间
移动设备目前我没有找到低延迟的解决方案,但是vlc至少可以播放rtsp流,于是暂时先使用vlc
录制
录制方案其实很简单:要么在推流端直接录制,要么使用ffmpeg或者是vlc客户端完成录制
测试
该方案可以基本达到最开始的要求,实测延迟400ms左右,1080p清晰画质,单个用户消耗带宽20-400kb/s。但是未在不支持显卡h265编码的设备上进行测试
但仍然出现了一些问题:在网络较差的情况下会出现严重花屏,丢包等问题
改善花屏
之前出现花屏的原因是因为拉流使用了tcp协议,而在buffer较小的时候使用tcp会导致雪崩式丢包,造成无法恢复的花屏,使用udp拉流可以改善该问题