我正在尝试通过 WebRTC 发送使用 h264 编码的视频流(使用 nvidia 编码器进行硬件加速),以便在浏览器上实现低延迟显示。
更准确地说,我有一个以固定帧速率对 opengl 帧缓冲区进行编码的线程,然后将生成的 AVPacket 数据(我使用 ffmpeg 的 C api 进行编码)通过 WebRTC 转发到客户端(使用 aiortc)
问题是我观察到明显的延迟,这似乎取决于我使用的帧速率。 例如,在本地运行它,以 30fps 运行时会出现大约 160ms 的延迟,以 90fps 编码时会出现大约 30ms 的延迟。
这里的延迟是测量的编码+传输+解码的时间,我有强烈的印象,问题发生在呈现视频帧时,就像浏览器没有立即呈现帧一样......(编码很快,我会期望本地设置上的传输速度也相当快,并且解码似乎也很好,如浏览器中的 RTP 统计数据所报告的那样)。
我尝试使用 RTP 时间戳,但这并没有改变任何东西,唯一影响延迟的变量是编码线程“频率”。
知道什么可能造成这种延迟吗?我是否缺少参数?
此外,这是我使用的编解码器选项:(根据我的实验,它们对延迟的影响并不大)
profile = high
preset = llhq # low latency, high quality
tune = zerolatency
zerolatency = 1
g = 2 * FRAME_PER_SECOND # key frame every 2s
strict-gop = 1
更新
我的印象是 Chrome 端的抖动缓冲区会阻止 rtp 数据包立即解码,这可能吗?
更新2
playout-delay
标头扩展稍微减少了延迟。playoudDelayHint
似乎也有一点帮助更新3
经过进一步调查,我得出的结论是,通过视频流的标准 webrtc 不可能获得更低的延迟,因为对视频缓冲几乎没有控制,我认为这是造成这种情况的原因。观察到延迟。
顺便说一句,我尝试检查 google stadia 是如何做到这一点的,因为他们似乎也使用 WebRTC,但他们使用一些内部框架......(加上 Chrome 是唯一受支持的浏览器)
如果您将 NvFBC 与 NvENC 一起使用,则不应使用 ffmpeg 来编码帧,将帧缓冲区存储为 opengl 纹理并将其提供给编码器,您当前正在将帧缓冲区数据从 VRAM 复制到系统内存,再复制回 VRAM然后再回来。他们网站上的 Nvidia Capture zip 文件中有一个示例。
我目前正在处理一个非常类似的问题,但抖动缓冲区堆积的原因可能是由于时间戳问题,而不是协议本身。
使用 RTP 播放延迟标头扩展稍微减少了延迟。
在浏览器中设置 playoudDelayHint 似乎也有助于 bitlockquote
我也有同样的问题(但由于某种原因,我的类似问题被版主关闭了),请详细解释一下这些点。 我尝试将这些行添加到服务器端的 SDP,但没有给出任何结果:
a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
a=playout-delay:0 1
我也尝试在客户端(JS)设置playoudDelayHint,但也没有什么区别。也许我做错了什么。在 JS 中,我尝试了这个:
pc.ontrack = function(event) {
var el = document.createElement(event.track.kind)
el.srcObject = event.streams[0]
el.autoplay = true
el.controls = true
el.preload = 'none'
el.buffered = false
if(event.track.kind === "video") {
event.receiver.playoutDelayHint = 0;
}
document.getElementById('remoteVideos').appendChild(el)
}