用 Golang 手搓视频直播?别慌,咱们一步步来

想搞个视频直播,翻了一堆文档,结果发现什么音视频编解码、RTMP协议、流媒体服务器……直接把人看懵了,别怕,今天咱们就用Golang...

想搞个视频直播,翻了一堆文档,结果发现什么音视频编解码、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 写控制层。

用 Golang 手搓视频直播?别慌,咱们一步步来

组件 用途 语言
Nginx-RTMP 接收推流、分发流、转HLS C
Golang 流管理API、鉴权、监控 Go
FFmpeg 推流、拉流转码 C

这种架构下,Golang 只负责两件事:

  1. 接收用户的推流请求,调用 FFmpeg 把本地文件推给 Nginx-RTMP
  2. 提供一个 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

(11)

文章推荐

发表回复

本站作者才能评论

评论列表(4条)

  • kyadmin
    kyadmin 2026-06-30

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

  • kyadmin
    kyadmin 2026-06-30

    希望本篇文章《用 Golang 手搓视频直播?别慌,咱们一步步来》能对你有所帮助!

  • kyadmin
    kyadmin 2026-06-30

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

  • kyadmin
    kyadmin 2026-06-30

    本文概览:想搞个视频直播,翻了一堆文档,结果发现什么音视频编解码、RTMP协议、流媒体服务器……直接把人看懵了,别怕,今天咱们就用Golang...

    联系我们

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

    关注我们