说实话,第一次让我用 Golang 做视频直播的时候,我心里也是打鼓的,视频直播听起来多高大上啊,又是推流又是拉流的,还得搞什么 HLS、RTMP 协议,但真上手之后发现,Go 语言的并发模型和标准库,简直就是为这事儿量身定做的,今天我就用大白话,把我踩过的坑和经验给你盘一遍。
视频直播到底在干啥?
先别急着写代码,咱得搞清楚视频直播的本质,视频直播说白了就是:
- 推流端:摄像头或者屏幕画面,被采集下来,一帧一帧地编码成视频数据。
- 服务端:接收这些数据,转发给所有想看的人。
- 播放端:浏览器或者手机 App 拿到数据,解码播放。
在 Go 里面,我们通常不会自己造轮子去搞 RTMP 这种底层协议——太累,而且容易出 bug,多数时候我们只需要写一个 HTTP 流媒体服务,或者用 WebRTC 来做低延迟直播,下面我重点说说两种常见做法。
用 Go + FFmpeg 搭建 HLS 直播
这是最稳妥、也是最容易上手的方案。HLS(HTTP Live Streaming)是苹果搞的协议,现在所有主流浏览器都支持,原理很简单:推流端不断生成一小段一小段的 .ts 视频文件,和一个 .m3u8 索引文件,播放器自动去拉最新的片段。
推流部分(Go 调用 FFmpeg)
我们写一个 Go 程序,启动 FFmpeg 进程来采集摄像头画面,并实时切片:
package main
import (
"os/exec"
"log"
)
func main() {
cmd := exec.Command("ffmpeg",
"-f", "avfoundation", // macOS 采集设备,Windows 用 dshow,Linux 用 v4l2
"-i", "0:0", // 第一个视频设备+音频设备
"-c:v", "libx264", // 视频编码
"-c:a", "aac", // 音频编码
"-f", "hls", // 输出格式 HLS
"-hls_time", "2", // 每个切片长度 2 秒
"-hls_list_size", "5",// 保留最近 5 个切片
"-hls_flags", "delete_segments",
"./live/stream.m3u8",
)
err := cmd.Run()
if err != nil {
log.Fatal("FFmpeg 挂了: ", err)
}
}
关键点:-hls_time 2 意思是每 2 秒生成一个 ts 文件,你可以根据网络状况调整,时间越短延迟越低,但服务器压力越大。
服务端(Go HTTP 服务器)
接下来我们写一个简单的 HTTP 服务器,用来提供这些文件给客户端,要注意的是:需要设置 CORS 头,否则浏览器播放器会报跨域错误。
package main
import (
"net/http"
)
func main() {
// 静态文件服务器,提供 .m3u8 和 .ts 文件
http.Handle("/live/", http.StripPrefix("/live/",
http.FileServer(http.Dir("./live"))))
// 给请求加上 CORS 头
http.ListenAndServe(":8080", corsMiddleware(http.DefaultServeMux))
}
func corsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return
}
next.ServeHTTP(w, r)
})
}
播放端直接用 <video> 标签,src 指向 http://你的IP:8080/live/stream.m3u8 就行,我用 hls.js 库做前端播放,兼容性更好。
这套方案的优缺点
| 优点 | 缺点 |
|---|---|
| 部署简单,FFmpeg 成熟稳定 | 延迟约 5-10 秒,不适合互动场景 |
| Go 代码量极少,主要调 FFmpeg | 需要服务器上安装 FFmpeg |
| 支持所有主流浏览器和播放器 | 切片文件占用磁盘空间,需要定时清理 |
纯 Go 实现 WebRTC 低延迟直播
如果你追求 <1 秒的延迟,比如做在线教育、远程控制,那得上 WebRTC,Go 这边有个很成熟的库叫 pion/webrtc,基本能让你用纯 Go 搞定信令和媒体流。
核心思路
WebRTC 需要两个东西:
- 信令服务器:用 Go 的 WebSocket 或者 HTTP 交换 SDP 信息(就是两个端点握手用的描述文件)。
- 媒体服务器:用 Go 接收一端的视频流,转发给另一端。
注意:纯 Go 做 WebRTC 的媒体处理很强大,但结合浏览器时,必须用 HTTPS(或者 localhost),否则浏览器会拒绝获取摄像头权限。
代码骨架(信令 + 转发)
这里我简化一下,只展示最关键的信令交换部分:
package main
import (
"encoding/json"
"net/http"
"github.com/gorilla/websocket"
"github.com/pion/webrtc/v3"
)
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool { return true },
}
func handleWebSocket(w http.ResponseWriter, r *http.Request) {
conn, _ := upgrader.Upgrade(w, r, nil)
defer conn.Close()
// 创建 PeerConnection
pc, _ := webrtc.NewPeerConnection(webrtc.Configuration{})
defer pc.Close()
// 当收到远程 SDP 时,打印并处理
conn.ReadMessage()
// 实际需要:解析 JSON SDP,调用 pc.SetRemoteDescription()
// 然后创建 Answer,通过 WebSocket 发回
}
func main() {
http.HandleFunc("/ws", handleWebSocket)
http.ListenAndServe(":8080", nil)
}
细节提醒:这里我没写全,因为 WebRTC 信令涉及 ICE 候选(网络地址协商)、音视频轨道的添加,代码会膨胀到 200 行以上,建议直接看 pion/webrtc 的官方示例,特别是 examples/play-from-disk 和 examples/save-to-disk。
什么时候用 WebRTC?
如果你的用户和主播在同一个局域网,或者你控制了网络环境(比如给企业做内网直播),WebRTC 是绝佳选择,但如果观众很多(超过 100 人),你还需要 SFU(选择性转发单元)架构,那就得用 LiveKit 或者 Janus 这类成熟方案,自己写 Go 服务端做 SFU 会累死。
直播服务器的关键考量
不管选哪种方案,有几个坑你得提前知道:
- 上行带宽:推流端的上传带宽决定了画质,一般 1080p 直播需要 3-5 Mbps 上行。
- 协议选择:HLS 兼容性好但延迟高;WebRTC 延迟低但需要支持 ICE 穿透(STUN/TURN 服务器)。
- 录制并存:如果同时要录像,可以用 FFmpeg 的
-map参数,或者用 Go 直接保存收到的 RTP 包。
最后说点实在的
我写这篇文章的时候,中间还跑去查了一下 pion/webrtc 的最新版本号——你看,做技术就是这样,边写边查边改,视频直播这东西,你要想一次性写出完美代码,基本不可能。最好的办法是先跑通 FFmpeg 的 HLS 方案,几行代码就能看到画面在浏览器里动起来,那种成就感会推着你往前走。
等你把 HLS 玩熟了,再琢磨 WebRTC 的低延迟玩法,别一上来就想搞个大新闻,先让画面动起来,再一点点打磨,毕竟,做直播最怕的不是延迟高,而是折腾半天啥也没出来。
希望下次你朋友问你“怎么做视频直播”的时候,能直接甩给他这篇带着 Go 代码的文章——别忘了让他先装个 FFmpeg。
本文来自作者[kyadmin]投稿,不代表中国·AC米兰(Milan)体育官方网站-Official Website立场,如若转载,请注明出处:http://www.graee.com/ty/256.html

评论列表(4条)
我是中国·AC米兰(Milan)体育官方网站-Official Website的签约作者“kyadmin”!
希望本篇文章《用 Golang 手撸一个视频直播?这事儿我干过,你也行》能对你有所帮助!
本站[中国·AC米兰(Milan)体育官方网站-Official Website]内容主要涵盖:AC米兰,ac米兰官网,AC米兰官网
本文概览:说实话,第一次让我用Golang做视频直播的时候,我心里也是打鼓的,视频直播听起来多高大上啊,又是推流又是拉流的,还得搞什么HLS...