用 Golang 手撸一个视频直播?这事儿我干过,你也行

说实话,第一次让我用Golang做视频直播的时候,我心里也是打鼓的,视频直播听起来多高大上啊,又是推流又是拉流的,还得搞什么HLS...

说实话,第一次让我用 Golang 做视频直播的时候,我心里也是打鼓的,视频直播听起来多高大上啊,又是推流又是拉流的,还得搞什么 HLSRTMP 协议,但真上手之后发现,Go 语言的并发模型和标准库,简直就是为这事儿量身定做的,今天我就用大白话,把我踩过的坑和经验给你盘一遍。

视频直播到底在干啥?

先别急着写代码,咱得搞清楚视频直播的本质,视频直播说白了就是:

  1. 推流端:摄像头或者屏幕画面,被采集下来,一帧一帧地编码成视频数据。
  2. 服务端:接收这些数据,转发给所有想看的人。
  3. 播放端:浏览器或者手机 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 需要两个东西:

  1. 信令服务器:用 Go 的 WebSocket 或者 HTTP 交换 SDP 信息(就是两个端点握手用的描述文件)。
  2. 媒体服务器:用 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-diskexamples/save-to-disk

什么时候用 WebRTC?

如果你的用户和主播在同一个局域网,或者你控制了网络环境(比如给企业做内网直播),WebRTC 是绝佳选择,但如果观众很多(超过 100 人),你还需要 SFU(选择性转发单元)架构,那就得用 LiveKit 或者 Janus 这类成熟方案,自己写 Go 服务端做 SFU 会累死。

用 Golang 手撸一个视频直播?这事儿我干过,你也行

直播服务器的关键考量

不管选哪种方案,有几个坑你得提前知道:

  • 上行带宽:推流端的上传带宽决定了画质,一般 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

(12)

文章推荐

发表回复

本站作者才能评论

评论列表(4条)

  • kyadmin
    kyadmin 2026-06-29

    我是中国·AC米兰(Milan)体育官方网站-Official Website的签约作者“kyadmin”!

  • kyadmin
    kyadmin 2026-06-29

    希望本篇文章《用 Golang 手撸一个视频直播?这事儿我干过,你也行》能对你有所帮助!

  • kyadmin
    kyadmin 2026-06-29

    本站[中国·AC米兰(Milan)体育官方网站-Official Website]内容主要涵盖:AC米兰,ac米兰官网,AC米兰官网

  • kyadmin
    kyadmin 2026-06-29

    本文概览:说实话,第一次让我用Golang做视频直播的时候,我心里也是打鼓的,视频直播听起来多高大上啊,又是推流又是拉流的,还得搞什么HLS...

    联系我们

    工作时间:周一至周五,9:30-18:30,节假日休息

    关注我们