跟进我之前的问题,我想询问使用 ffmpeg 进行实时视频流传输的替代方法(由于某些限制,我不想在这里讨论,因此 WebRTC 不是一个选项)。
背景:
我有一个 Go 应用程序,其中 Goroutine 启动 ffmpeg 来处理视频流,然后通过
chan []byte
将视频流传递到主 Goroutine。我尝试使用 WebSocket,但遇到了上一个问题中描述的问题。由于显着的延迟和视频上的绿色方块等伪影,HLS 也无法正常工作。
根据上一个问题中的评论,我尝试通过简单的 GET 请求来流式传输视频。这是我实现的 Go 处理程序:
func stream(helperApp agent.Helper) func(rw http.ResponseWriter, rr *http.Request) {
a := atomic.Bool{}
return func(rw http.ResponseWriter, rr *http.Request) {
if !a.CAS(false, true) {
http.Error(rw, "already running", http.StatusInternalServerError)
return
}
rw.Header().Set("Access-Control-Allow-Origin", "*")
rw.Header().Set("Content-Type", "video/mp2t")
out := make(chan []byte)
// create StreamParam
go ScreenCaptureForLiveStream(StreamParam, out) // ffmpeg process starts inside
r, w := io.Pipe()
go func() {
for data := range out {
w.Write(data)
fmt.Println(len(data))
}
}()
io.Copy(rw, r)
}
}
在客户端(HTML):
<video id="video" muted="muted" src="http://localhost:8080/stream" controls></video>
在浏览器控制台中,我可以看到正在接收数据,但视频无法播放。
FFmpeg 使用以下参数执行:
-loglevel error -f avfoundation -framerate 5 -capture_cursor 1 -capture_mouse_clicks 1 -i 1 -c:v libx264 -pix_fmt yuv420p -vf pad='ceil(iw/2)*2:ceil(ih/2)*2' -threads 0 -preset veryfast -bf 2 -f mpegts pipe:1
为了验证,我跑了:
ffmpeg -i http://localhost:8080/stream -c copy out.mp4
视频已成功保存并播放。
问题: 除了 WebRTC 之外,还有哪些替代方法可以使用 ffmpeg 实现实时视频流?为什么当前通过 HTTP GET 请求流式传输视频的方法在浏览器中无法正常运行,如何解决这个问题?
您将无法将 MPEG-TS 发送到视频元素。 我建议您使用 WebM 或 MP4。
对于 WebM,在 FFmpeg 命令中使用
-f webm
,然后对于 Content-Type
使用 video/webm
。
对于 MP4,您还必须配置分段,因此使用
-f mp4 -movflags frag_keyframe+empty_moov
,然后对于 Content-Type
,使用 video/mp4
。
如果您的
Content-Type
中还包含编解码器,则可以减少缓冲时间。
此外,由于您的直播是“直播”,我强烈建议您在视频标签中设置
preload="none"
。 否则,即使用户没有播放视频,浏览器也可能会毫无意义地进行流式传输。
如果您想更好地控制延迟,请密切关注
buffered
属性,并让 playbackRate
稍微超过 1.0
以赶上实时。 但不要走得太远,否则会出现缓冲区不足。 当然,如果发生了根本性的事情,并且您发现自己落后了 20 秒,您可以随时将 currentTime
设置为最新时间。
使用这些方法,我无需特殊优化即可将玻璃到玻璃的速度控制在 300 毫秒以下。 如果您仔细控制编解码器参数,您可以低于这个值...请记住,一切都是权衡。