想搞个视频直播,翻了一堆文档,结果发现什么音视频编解码、RTMP 协议、流媒体服务器……直接把人看懵了,别怕,今天咱们就用 Golang 来干这件事,Golang 的并发模型和标准库简直是为这种场景量身定做的,再加上一些开源库,你也能写一个能跑起来的直播推流拉流程序。
视频直播到底在直播什么?
先别急着写代码,咱们得搞清楚视频直播到底是在做什么,视频直播就是:你这边采集画面和声音 → 编码压缩 → 通过网络推送到服务器 → 其他人从服务器拉流 → 解码播放。
这里面最核心的部分是 流媒体传输协议,常见的公司都用 RTMP(Adobe RTMP标准)、HLS(Apple HTTP Live Streaming)、WebRTC,我们今天主要用 RTMP,因为它推流延迟低,Golang 生态里有个库叫 joy4 可以处理。
环境搭建:Golang 能做什么?
你不需要自己从零写编解码器,那是 C/C++ 人才干的事,Golang 的优势在于做 高并发的流媒体中转和分发服务,我们只需要调用 FFmpeg 来做推流和拉流,然后用 Golang 写一个服务来控制和管理这些流。
首先你得安装好:
- Golang 1.18+
- FFmpeg(用来推流,记得加到系统环境变量)
- 一个能看懂终端输出的眼睛
用 Go Modules 初始化项目:
mkdir live-streaming cd live-streaming go mod init live-streaming
核心逻辑:用 Goroutine 管理多个流
Golang 最帅的地方就是 Goroutine,假设你要同时拉流、推流、处理多个用户的请求,传统的语言得写一堆线程池代码,Go 里就是几行 go func() 的事。
你写一个函数来启动一个流处理任务:
func processStream(streamUrl string) {
// 这行代码会在一个新的 goroutine 里跑
go func() {
// 用 FFmpeg 命令行来推流
cmd := exec.Command("ffmpeg", "-i", streamUrl, ...)
cmd.Run()
}()
}
这只是一个思路,别这么直接复制,因为 FFmpeg 的参数很变态,咱们下面会细说。
推流端:用 FFmpeg + Golang 包装
推流的任务就是把本地的视频文件或者摄像头画面变成 RTMP 流,假设你有个视频文件 input.mp4,想推送到 rtmp://localhost/live/stream1,最原生的命令是这样:
ffmpeg -re -i input.mp4 -c copy -f flv rtmp://localhost/live/stream1
这里面 -re 是关键,它让 FFmpeg 以原始帧率读取文件,模拟实时推流。
在 Golang 里包装这个命令,你得处理输入输出和错误:
package main
import (
"os/exec"
"log"
)
func PushStream(inputVideo string, rtmpUrl string) error {
// 注意:这里需要加 -re 参数来模拟实时
cmd := exec.Command("ffmpeg",
"-re", // 实时推流
"-i", inputVideo, // 输入文件
"-c", "copy", // 不重新编码,直接复制流
"-f", "flv", // 输出格式是 FLV(RTMP需要)
rtmpUrl, // RTMP 地址
)
// 把标准输出和错误重定向到控制台,方便排错
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
log.Printf("开始推流: %s -> %s", inputVideo, rtmpUrl)
return cmd.Run()
}
这里有个坑:-c copy 意味着 你的视频编码必须是 H.264,因为 RTMP 标准只支持 H.264 和 AAC,如果你的视频是其他编码,请先转码。
拉流端:从 RTMP 拉取并转成 HLS
光能推还不够,用户要看啊,拉流的做法一般是:服务端从 RTMP 拉流,然后转成 HLS(HTTP Live Streaming),这样用户用浏览器 <video> 标签就能看,不需要安装任何插件。
这个任务也可以交给 FFmpeg,下面这个命令把 RTMP 流实时转成 M3U8 + TS 文件:
ffmpeg -i rtmp://localhost/live/stream1 -c copy -f hls -hls_time 2 -hls_list_size 5 -hls_flags delete_segments /tmp/hls/stream1.m3u8
-hls_time 2:每个切片时长2秒-hls_list_size 5:播放列表里存最近5个切片-hls_flags delete_segments:自动删除旧切片,省硬盘空间
在 Golang 里,同样用 exec.Command 执行,但要小心文件路径权限,你可以加个简单的并发控制,比如用 Channel 来限制同时转码的流数量。
type StreamTranscoder struct {
maxJobs int
jobChan chan string
}
func NewTranscoder(max int) *StreamTranscoder {
return &StreamTranscoder{
maxJobs: max,
jobChan: make(chan string, max),
}
}
func (t *StreamTranscoder) Start(rtmpUrl, hlsOutput string) {
go func() {
// 使用 Channel 控制并发数
t.jobChan <- "busy"
defer func() { <-t.jobChan }()
cmd := exec.Command("ffmpeg",
"-i", rtmpUrl,
"-c", "copy",
"-f", "hls",
"-hls_time", "2",
"-hls_list_size", "5",
"-hls_flags", "delete_segments",
hlsOutput,
)
cmd.Run()
}()
}
用 Gin 写一个简单的 Web 管理接口
现在推流和转码都能跑了,但全在命令行里敲命令太原始了,咱们用 Gin (Go的Web框架)写几个接口,方便用户管理直播。
安装 Gin:
go get -u github.com/gin-gonic/gin
写一个超级简约的结构:
package main
import (
"github.com/gin-gonic/gin"
"net/http"
)
var streamManager = NewStreamManager() // 自己实现一个管理器
func main() {
r := gin.Default()
// 创建直播流
r.POST("/stream", func(c *gin.Context) {
name := c.Query("name")
input := c.Query("input")
// 假设 name 是流名称,input 是本地视频路径
go PushStream(input, "rtmp://localhost/live/"+name)
c.JSON(http.StatusOK, gin.H{"status": "推流中"})
})
// 获取所有流的状态
r.GET("/streams", func(c *gin.Context) {
// 返回流列表和状态
c.JSON(http.StatusOK, streamManager.GetAllStreams())
})
r.Run(":8080")
}
你可以在结构体里用 sync.Map 来保存所有流的 Goroutine 状态,这样安全又方便。
常见坑和填坑指南
编码问题
很多视频是 H.265 编码,但 RTMP 不支持,解决办法:在 FFmpeg 参数里把 -c copy 改成 -c:v libx264 -preset ultrafast -c:a aac,这样服务端转码,但 CPU 开销很大,可以用 NVIDIA 的 NVENC 加速(-c:v h264_nvenc)。
延迟问题
默认的 RTMP 延迟可能在3-5秒,如果觉得太高,可以调 FFmpeg 的 -g(GOP大小)和 -tune zerolatency。
ffmpeg -re -i input.mp4 -c:v libx264 -preset ultrafast -tune zerolatency -c:a aac -f flv rtmp://...
断流自动重连
直播流断了怎么办?最简单粗暴的做法:用 for 循环 包起来,加上延迟重试。
func PushStreamWithRetry(input, rtmpUrl string) {
for {
err := PushStream(input, rtmpUrl)
if err != nil {
log.Printf("推流出错,10秒后重连: %v", err)
time.Sleep(10 * time.Second)
}
}
}
真实落地的方案:Nginx-RTMP + Golang
其实在实际生产中,很少人用纯 Golang 当 RTMP 服务器(虽然 joy4 可以),更常见的是:Nginx + nginx-rtmp-module 做流媒体服务器,Golang 写控制层。

| 组件 | 用途 | 语言 |
|---|---|---|
| Nginx-RTMP | 接收推流、分发流、转HLS | C |
| Golang | 流管理API、鉴权、监控 | Go |
| FFmpeg | 推流、拉流转码 | C |
这种架构下,Golang 只负责两件事:
- 接收用户的推流请求,调用 FFmpeg 把本地文件推给 Nginx-RTMP
- 提供一个 Web 页面让用户查看有哪些流在直播
Nginx-RTMP 的配置很简单:
rtmp {
server {
listen 1935; # RTMP 端口
application live {
live on;
hls on;
hls_path /tmp/hls;
}
}
}
Golang 就往 rtmp://localhost/live/stream1 推流,Nginx 自动转成 HLS 放在 /tmp/hls/stream1.m3u8,用户直接访问 http://你的IP/hls/stream1.m3u8 就能看。
视频直播听起来高大上,拆开来其实就三件事:推、转、拉,Golang 负责中间那个很烦的并发管理和API,FFmpeg 负责真正干活的编解码,Nginx 负责给用户分发,你不需要精通音视频,只要理解 Goroutine + Channel + 命令行调用 这个模式,就能搭一个能用的直播系统。
我写这篇的时候也掉了一些坑,比如一开始忘了加 -re 参数,推流快得跟鬼一样,后来翻了一天文档才发现,这些经验现在就当送你了,快去试试吧,搞不好能弄出个直播软件来呢。
本文来自作者[kyadmin]投稿,不代表中国·AC米兰(Milan)体育官方网站-Official Website立场,如若转载,请注明出处:http://manukahealth.com.cn/nba/827.html
评论列表(4条)
我是中国·AC米兰(Milan)体育官方网站-Official Website的签约作者“kyadmin”!
希望本篇文章《用 Golang 手搓视频直播?别慌,咱们一步步来》能对你有所帮助!
本站[中国·AC米兰(Milan)体育官方网站-Official Website]内容主要涵盖:AC米兰,ac米兰官网,AC米兰官网
本文概览:想搞个视频直播,翻了一堆文档,结果发现什么音视频编解码、RTMP协议、流媒体服务器……直接把人看懵了,别怕,今天咱们就用Golang...