Go 流媒体开发工具包 — 协议接入、编解码与流编排;生产交付请以 stable 能力为边界,实验/占位能力见下文说明。
| 类别 | 支持项 |
|---|---|
| 传输协议 | RTSP/RTSPS, RTMP/RTMPS, SRT, RIST, HLS, WebRTC (WHIP/WHEP), GB/T 28181, NDI(需外部SDK), DVR-IP |
| 容器格式 | MP4, fMP4, FLV, MPEG-TS, MKV(以 demux 为主), HLS, AAC, MSE, RAW |
| 视频编码 | H.264, H.265/HEVC, AVS2, VP9, AV1, VVC/H.266, MJPEG |
| 音频编码 | AAC, Opus, MP3, FLAC, AC-3/E-AC-3, G.726, PCM (μ-law/A-law) |
| 图片编码 | WebP, AVIF, HEIF |
| 硬件加速 | NVENC, QSV, AMF, VAAPI, VideoToolbox, V4L2M2M, RKMPP(依赖 CGO/FFmpeg 环境) |
| 高级功能 | 字幕 (SRT/ASS/WebVTT/CEA-608/708), OpenTelemetry 追踪, Prometheus 指标;ABR/录制多云后端/集群多后端详见“能力边界说明” |
format.RegisterAll() 稳定协议集stream / pkg/manager / pkg/streammgr 的单进程流会话治理pkg/recording.LocalStoragepkg/cluster.StaticDiscoverystream.Transcode):需 ffmpeg7/ffmpeg8 build tag;未启用时走 stub 并返回错误(stream/transcoder_stub.go)。pkg/abr):保留 Ladder/配置与进度模型,但 NewTranscoder 会直接返回错误,当前不可用于生产转码交付(pkg/abr/transcoder.go)。pkg/recording):LocalStorage 可用;NewS3Storage/NewGCSStorage 在构造阶段直接返回错误;Recorder.createMuxer 仍未实现,录制主流程未完全落地(pkg/recording/recorder.go)。pkg/cluster):StaticDiscovery 可用;NewConsulDiscovery / NewEtcdDiscovery / NewK8sDiscovery 在构造阶段直接返回错误,不应视为已接入真实服务发现后端(pkg/cluster/discovery.go)。pkg/abr、云录制后端、多后端 discovery 当作已交付能力接入。format.RegisterAll()。cmd/vdk serve 适合单进程、单节点、边车式交付;不承诺分布式控制面、高可用选主、持久化会话恢复。HLSDir / 录制目录应挂载到持久卷;不要将临时目录直接视为生产持久层。gofmt / go vet / go test ./...,建议在发布前额外执行 go test -race ./...。cmd/vdk serve 已补齐 logging.level / logging.format / metrics / livez|readyz 接缝;生产环境仍应统一接入外部日志、指标与追踪系统。仓库内置 Go CI(见 .github/workflows/go-ci.yml),默认执行:
gofmt -l:格式一致性go vet ./...:静态分析go test ./...:全模块回归建议将上述三项视为所有变更合并前的最低门槛。
go get cnb.cool/svn/vdk@latest
go install cnb.cool/svn/vdk/cmd/vdk@latest
# 探测流信息
vdk probe rtsp://example.com/live/stream
# 转码
vdk transcode -i input.mp4 -o output.flv
# 启动流媒体服务
vdk serve -c config.yaml
# 性能基准测试
vdk benchmark
package main
import (
"context"
"time"
"cnb.cool/svn/vdk/format"
"cnb.cool/svn/vdk/stream"
)
func main() {
format.RegisterAll()
s, err := stream.New().
Name("cam-01").
Input("rtsp://admin:pass@192.168.1.100/live").
WithTimeout(10 * time.Second).
LowLatency().
Output("rtmp://cdn.example.com/live/cam-01").
WithTimeout(5 * time.Second).
Done().
Output("srt://backup.example.com:9000").
SRTConfig(120*time.Millisecond, "secret", "live/cam-01").
Done().
Build()
if err != nil {
panic(err)
}
s.OnEvent(func(e stream.EventData) {
switch e.Event {
case stream.EventReconnecting:
println("重连中...")
case stream.EventError:
println("错误:", e.Error.Error())
}
})
if err := s.Run(context.Background()); err != nil {
panic(err)
}
}
s, err := stream.New().
Input("rtsp://camera.local/stream").
Transcode().
Video(stream.VideoH265).
Resolution(1920, 1080).
BitrateM(4).
Preset(stream.PresetFast).
Done().
Audio(stream.AudioAAC).
Done().
Done().
Output("/recordings/output.mp4").Done().
Build()
package main
import (
"cnb.cool/svn/vdk/av/avutil"
"cnb.cool/svn/vdk/format"
)
func main() {
format.RegisterAll()
demuxer, err := avutil.Open("rtsp://example.com/live")
if err != nil {
panic(err)
}
defer demuxer.Close()
muxer, err := avutil.Create("output.mp4")
if err != nil {
panic(err)
}
defer muxer.Close()
streams, _ := demuxer.Streams()
muxer.WriteHeader(streams)
avutil.CopyPackets(muxer, demuxer)
muxer.WriteTrailer()
}
av/event 包提供协议传输层的通用事件机制,14 种事件类型覆盖连接全生命周期。
package main
import (
"fmt"
"cnb.cool/svn/vdk/av/event"
"cnb.cool/svn/vdk/format/srt"
)
func main() {
conn, err := srt.Dial("srt://relay.example.com:9000?streamid=live/test")
if err != nil {
panic(err)
}
defer conn.Close()
// 通过 EventBus 监听事件
conn.EventBus = event.NewBus()
conn.EventBus.On(event.Connected, func(d event.Data) {
fmt.Printf("[%s] 已连接: %s\n", d.Protocol, d.URL)
})
conn.EventBus.On(event.StreamReady, func(d event.Data) {
fmt.Printf("流就绪, codec 数量: %d\n", len(d.Codec))
})
conn.EventBus.On(event.Stats, func(d event.Data) {
if stats, ok := d.Stats.(srt.Stats); ok {
fmt.Printf("RTT: %dms, 丢包率: %.2f%%\n",
stats.RTT.Milliseconds(), stats.PacketLossRate*100)
}
})
conn.EventBus.On(event.Error, func(d event.Data) {
fmt.Printf("错误: %v\n", d.Error)
})
// OnAll 接收所有事件
conn.EventBus.OnAll(func(d event.Data) {
fmt.Printf("[%s] %s @ %s\n", d.Protocol, d.Event, d.Time.Format("15:04:05"))
})
}
import "cnb.cool/svn/vdk/av/event"
// 将任意 DemuxCloser 包装为带事件的 HookDemuxer
hooked := event.WrapDemuxer(demuxer,
event.WithProtocol("rtsp"),
event.WithURL("rtsp://example.com/live"),
event.WithDirection("subscribe"),
)
hooked.On(event.StreamReady, func(d event.Data) {
fmt.Println("codec 就绪:", d.Codec)
})
streams, err := hooked.Streams() // 自动发射 StreamReady
| 事件 | 说明 |
|---|---|
Connecting | 正在连接 |
Connected | 连接成功 |
Handshaking | 正在握手 |
Handshaked | 握手完成 |
StreamReady | 流就绪 (codec 已获取) |
PacketRead | 读取数据包 |
PacketWrite | 写入数据包 |
CodecChange | 编码变更 |
Error | 错误 |
Disconnecting | 正在断开 |
Disconnected | 已断开 |
Reconnecting | 正在重连 |
Reconnected | 重连成功 |
Stats | 统计信息更新 |
vdk/ ├── av/ # 核心抽象层 │ ├── av.go # Muxer, Demuxer, CodecData, Packet 接口 │ ├── event/ # 事件系统 (Bus, HookDemuxer, HookMuxer) │ ├── pktque/ # 包队列与 Filter (WaitKeyFrame, FixTime) │ ├── pubsub/ # 发布/订阅 Queue (fan-out) │ ├── avutil/ # Handler 注册, Open/Create 辅助函数 │ ├── avconv/ # 格式转换辅助 │ └── transcode/ # 转码器包装 ├── codec/ # 编解码器 │ ├── h264parser/ # H.264 解析 (SplitNALUs, SPS, CodecData) │ ├── h265parser/ # H.265/HEVC 解析 │ ├── aacparser/ # AAC 解析 │ ├── opusparser/ # Opus 解析 │ ├── vp9parser/ # VP9 解析 │ ├── av1parser/ # AV1 解析 │ ├── vvc/ # VVC/H.266 │ ├── flac/ # FLAC │ ├── mp3/ # MP3 │ ├── ac3/ # AC-3 │ ├── mjpeg/ # MJPEG │ ├── webp/, avif/, heif/ # 图片格式 │ └── fake/ # 测试用假编码器 ├── format/ # 协议与容器 │ ├── rtmp/ # RTMP (Dial, Server, Conn + EventBus) │ ├── rtsp/ # RTSP Client + EventBus │ ├── rtspv2/ # RTSPv2 Client, ProxyConn, Server + EventBus │ ├── srt/ # SRT (Dial/DialContext/DialConfig, Config, Stats + EventBus) │ ├── rist/ # RIST (Sender, FEC, Stats, BridgeEvents) │ ├── webrtc/ # WebRTC Muxer, WebRTCPusher (WHIP/BatchV2), WHEPPuller │ ├── webrtcv3/ # WebRTC v3 兼容层 │ ├── gb28181/ # GB/T 28181 SIP + PS 解封装 │ ├── ndi/ # NDI 协议框架 │ ├── dvrip/ # DVR-IP Client + EventBus │ ├── hls/ # HLS Muxer │ ├── flv/ # FLV Muxer, Demuxer, Prober │ ├── mp4/ # MP4 Muxer, Demuxer │ ├── mp4f/ # fMP4 Muxer (fragmented) │ ├── mp4m/ # MP4 Muxer, Demuxer (扩展) │ ├── fmp4/ # fMP4 MovieFragmenter │ ├── mkv/ # MKV Demuxer │ ├── ts/ # MPEG-TS Muxer, Demuxer │ ├── nvr/ # NVR 录制 Muxer │ ├── aac/ # AAC 文件 │ ├── raw/ # RAW 裸流 │ └── mse/ # Media Source Extensions ├── stream/ # 高级 Builder API │ ├── builder.go # New(), Input(), Output(), Transcode(), Build() │ ├── stream.go # Stream (Start/Stop/Pause/Resume/Run/Wait) │ └── enums.go # Protocol, VideoCodec, AudioCodec, Container, Preset... ├── pkg/ # 功能模块 │ ├── manager/ # 流生命周期 Manager (状态机, 健康检查, 资源限制) │ ├── streammgr/ # 批量会话 Manager (熔断, 健康监控, 集群) │ ├── abr/ # ABR 框架(Ladder 完整;转码执行路径待落地) │ ├── ai/ # AI 增强 (超分/降噪/插帧/色彩/防抖/去隔行) │ ├── audio/ # 音频处理 (响度标准化, 混音, 声道映射) │ ├── subtitle/ # 字幕 (SRT/ASS/WebVTT/CEA-608/708) │ ├── recording/ # 分段录制框架(Local 可用;S3/GCS 占位) │ ├── cluster/ # 集群(Static 可用;Consul/Etcd/K8s 为骨架) │ ├── tracing/ # OpenTelemetry 分布式追踪 │ ├── config/ # 配置管理 │ └── scene/ # 场景检测 (内容类型识别, 编码建议) ├── cgo/ # FFmpeg CGO 绑定 │ ├── codec/ # 编解码 (H264/H265/VP9/AV1, 硬件加速) │ ├── filter/ # 滤镜 (构建器, 水印, 色调映射) │ ├── pipeline/ # 转码管道 (批量管理, 健康检查) │ └── sdk/ # 高级转码 SDK (引擎, 任务, 预设) ├── cmd/vdk/ # CLI 工具 (probe, transcode, serve, benchmark) ├── example/ # 示例程序 └── utils/ # 通用工具 (位流读写, 字节序转换)
| 模块 | 路径 | 说明 |
|---|---|---|
| 核心接口 | av/ | Muxer, Demuxer, CodecData, Packet |
| 事件系统 | av/event/ | Bus, HookDemuxer, HookMuxer |
| 包队列 | av/pktque/ | Filter, WaitKeyFrame, FixTime |
| 发布订阅 | av/pubsub/ | Queue fan-out |
| 工具函数 | av/avutil/ | Open, Create, CopyPackets |
| 格式转换 | av/avconv/ | 音频编码自动转换 |
| 转码器 | av/transcode/ | 音频转码包装 |
| 编解码器 | codec/ | H.264/H.265/AAC/Opus/VP9/AV1/VVC 等解析 |
| RTMP | format/rtmp/ | Dial, Server, Conn + EventBus |
| RTSP | format/rtsp/ | Client + EventBus |
| RTSPv2 | format/rtspv2/ | RTSPClient(主路径), ProxyConn/Server(轻量骨架) |
| SRT | format/srt/ | Dial, Config, Stats + EventBus |
| RIST | format/rist/ | Sender, FEC, Config + EventBus |
| WebRTC | format/webrtc/ | Muxer, WHIP/WHEP Pusher/Puller |
| GB/T 28181 | format/gb28181/ | SIP 注册/鉴权, PS 解封装 |
| DVRIP | format/dvrip/ | DVR/NVR 设备客户端 + EventBus |
| NDI | format/ndi/ | NDI 协议框架 (需外部 SDK) |
| FLV | format/flv/ | Muxer, Demuxer, Prober |
| MP4 | format/mp4/ | Muxer, Demuxer |
| fMP4 | format/fmp4/ | Fragmented MP4 |
| HLS | format/hls/ | M3U8 + TS 分片 |
| MPEG-TS | format/ts/ | Muxer, Demuxer |
| MKV | format/mkv/ | Demuxer (扩展) |
| MSE | format/mse/ | Media Source Extensions |
| RAW | format/raw/ | H.264/H.265 裸流 |
| NVR | format/nvr/ | 录像格式 |
| Builder API | stream/ | New, Build, Stream |
| 流管理器 | pkg/manager/ | 生命周期管理 |
| 会话管理 | pkg/streammgr/ | 批量会话, 熔断, 健康监控 |
| ABR | pkg/abr/ | 码率阶梯与编排框架(转码执行路径占位) |
| AI 增强 | pkg/ai/ | 超分/降噪/插帧 |
| 字幕 | pkg/subtitle/ | SRT/ASS/WebVTT/CEA-608/708 |
| 音频处理 | pkg/audio/ | 响度标准化, 混音, 声道映射 |
| 录制 | pkg/recording/ | 录制框架;Local 可用,S3/GCS 占位 |
| 集群 | pkg/cluster/ | 负载均衡/路由 + Static 发现可用;多后端发现待实现 |
| 指标 | pkg/metrics/ | Prometheus Collector |
| 追踪 | pkg/tracing/ | OpenTelemetry |
| 配置管理 | pkg/config/ | 统一配置加载 |
| 场景检测 | pkg/scene/ | 内容类型识别, 编码建议 |
| CGO 编解码 | cgo/codec/ | FFmpeg 编解码, 硬件加速 |
| CGO 滤镜 | cgo/filter/ | 滤镜构建器, 水印 |
| CGO 管道 | cgo/pipeline/ | 转码管道, 批量管理 |
| CGO SDK | cgo/sdk/ | 高级转码引擎 |
| CLI | cmd/vdk/ | probe, transcode, serve, benchmark |
| 示例 | example/ | 完整示例程序 |
| 版本 | 状态 | 重点 |
|---|---|---|
| v2.1 | 当前 | Builder API, 事件系统, SRT/RIST/WebRTC, GB/T 28181, AI 增强;ABR/录制/集群部分能力为实验或骨架 |
| v2.2 | 规划中 | DASH 输出, SRT Bonding, RIST Main Profile 完善, CMAF |
| v3.0 | 规划中 | 全链路 zero-copy, io_uring 传输, QUIC 协议, WebTransport |
| 依赖 | 用途 |
|---|---|
| pion/webrtc v3 / v4 | WebRTC (WHIP/WHEP) |
| pion/rtp | RTP 包处理 |
| gobwas/ws | WebSocket |
| go-astiav | FFmpeg CGO 绑定 |
| gopsutil | 系统资源监控 |
| OpenTelemetry | 分布式追踪 |
| google/uuid | UUID 生成 |
| x/crypto | 加密 |
| x/image | 图片处理 |
本项目基于 joy4 演进,感谢原作者的开创性工作。
MIT License
最后更新:2026-02-26