Go+FFmpeg实战:如何高效处理YUV数据并推RTMP流
·
背景痛点
在视频处理场景中,YUV数据的高效处理和RTMP推流是常见的需求,但开发者往往会遇到以下问题:
- 内存占用高:YUV原始数据体积大,尤其是高分辨率场景下(如1080P),单帧可达数MB
- 延迟波动大:传统FFmpeg命令行模式需频繁启停进程,管道传输带来额外开销
- 并发能力弱:多路流处理时资源竞争严重,难以利用多核优势

技术选型
方案对比
- 纯FFmpeg命令行
- 优点:配置简单,适合快速验证
-
缺点:进程间通信开销大,无法精细控制内存
-
Go绑定FFmpeg C库
- 优点:直接内存操作,支持协程级并发
- 缺点:需要处理CGO兼容性问题
核心实现
1. YUV内存管理
采用内存池技术避免重复分配:
type YUVPool struct {
buffers chan *[]byte
width int
height int
}
func NewYUVPool(width, height, capacity int) *YUVPool {
pool := &YUVPool{
buffers: make(chan *[]byte, capacity),
width: width,
height: height,
}
// 预分配内存
for i := 0; i < capacity; i++ {
size := width * height * 3 / 2 // YUV420格式
buf := make([]byte, size)
pool.buffers <- &buf
}
return pool
}
2. FFmpeg CGO调用
关键配置参数示例:
/*
#cgo pkg-config: libavformat libavcodec
#include <libavcodec/avcodec.h>
*/
import "C"
func setupEncoder() {
codec := C.avcodec_find_encoder(C.AV_CODEC_ID_H264)
ctx := C.avcodec_alloc_context3(codec)
ctx.bit_rate = 4000000
ctx.width = 1920
ctx.height = 1080
ctx.time_base = (C.AVRational){1, 25}
ctx.pix_fmt = C.AV_PIX_FMT_YUV420P
}
3. 并发架构设计

- 生产者协程:从摄像头/文件读取YUV数据
- 处理器协程:执行缩放/滤镜等操作
- 推送协程:通过独立连接发送RTMP流
性能测试
| 分辨率 | 纯FFmpeg(ms) | Go方案(ms) | 内存节省 | |---------|-------------|-----------|---------| | 720P | 42 | 28 | 35% | | 1080P | 78 | 51 | 48% | | 4K | 215 | 139 | 52% |
避坑指南
- CGO内存泄漏:确保所有AVFrame通过av_free释放
- 时间戳同步:手动计算pts时注意time_base转换
- 并发安全:每个推流协程使用独立的AVFormatContext
思考题
当需要合并多路视频流时,如何设计缓冲区策略才能平衡延迟和内存消耗?欢迎在评论区分享你的方案。
更多推荐


所有评论(0)