用Go语言做一周年纪念视频,365天的代码与爱
- 足球
- 2026-07-20 13:05:48
- 97
说实话,最开始我想做一周年纪念视频的时候,脑子里全是“用Adobe Premiere吧”或者“找在线模板套一套”,但后来想想,我和对象都是程序员,相恋365天,不如用我们最熟悉的方式来记录——写代码,用Go语言来生成视频,听起来很折腾,但当你把每一帧都变成代码逻辑的时候,那种掌控感特别真实。
为什么选Go语言做纪念视频?
你可能觉得,做视频不是应该用Python或者JavaScript吗?Go语言不是用来做后端服务的吗?但恰恰是因为Go的简洁和并发能力,让批量处理图片、合成帧、加音频这些操作变得特别顺手,我试过用Python的moviepy,但处理几百张图片的时候内存经常炸,换成Go之后,用goroutine并行处理每一帧,速度直接起飞。
核心思路:把365天变成365帧
我的做法很简单:每天一张照片,或者每天一个文字记录,把365天的数据存成一个CSV文件,然后用Go读取这个文件,逐帧生成图片,最后合成视频。
// 伪代码思路
type Day struct {
Date string
Photo string
Message string
}
func generateFrame(day Day) image.Image {
// 读取照片
// 叠加文字
// 返回一帧
}
这个逻辑看起来简单,但实际踩了很多坑,比如时间格式处理,Go的time包虽然强大,但新手容易在时区上翻车——你肯定不想纪念视频里的日期显示错误吧?
动手之前先搭好框架
我写了一个小项目,主要分三个模块:
| 模块 | 作用 | 关键点 |
|---|---|---|
| 数据加载器 | 读取CSV,校验数据完整性 | 处理空值、日期解析 |
| 帧生成器 | 根据模板生成每一帧图片 | 文字居中、图片缩放 |
| 视频合成器 | 将帧序列编码成MP4 | 帧率控制、音频混流 |
表格里写的很简单,但实际调试的时候,光图片缩放就折腾了我一晚上。 Go的image标准库功能很全,但不支持复杂的字体渲染——这时我引入了golang.org/x/image/font包,配合github.com/golang/freetype才搞定中文字体显示。
踩坑实录:中文字体和路径
如果你也想用Go做周年纪念视频,第一个要面对的问题就是中文字体,Go默认没有中文字体包,你需要自己找字体文件(比如思源黑体),然后加载:
// 加载字体文件
fontBytes, _ := ioutil.ReadFile("./fonts/SourceHanSansSC-Regular.otf")
font, _ := freetype.ParseFont(fontBytes)
还有一个坑是路径处理。不同操作系统下,文件路径的分隔符不一样,我一开始在Windows上写的代码,部署到Mac上就崩了,后来统一用filepath.Join才解决。
365天怎么组织比较有感觉?
我不希望视频只是照片堆砌,所以按 “四季+特殊日子” 来分组:
- 春(第1-90天):初识时的聊天记录截图,配淡淡的粉色背景
- 夏(第91-180天):一起出去玩拍的风景,加亮色滤镜
- 秋(第181-270天):日常吃饭、散步的随手拍,暖色调
- 冬(第271-365天):跨年、春节、纪念日近期的照片,深色背景配星星
每一帧停留时间我设成2秒,但遇到纪念日、生日这种特殊日子,手动把停留时间改成3秒,加个放大动画,这个逻辑用Go的time.Ticker很好控制。
// 控制每帧显示时间
func (v *Video) AddFrame(img image.Image, duration time.Duration) {
for i := 0; i < int(duration.Seconds()*v.FPS); i++ {
v.frames = append(v.frames, img)
}
}
说实话,写这个循环的时候我自己都笑了——一周年纪念视频,竟然是用对帧数做乘法算出来的。
音频同步:一个差点劝退的环节
视频不能没声音,我选了《You Are My Sunshine》的钢琴版(网上的免费版权音乐),但音频和画面的同步真的让人头大。
Go标准库不支持直接编码音频,我用了github.com/tosone/minimp3来解码MP3,然后用github.com/asticode/go-astits来混流,这里我必须坦白:最后合成MP4我用了FFmpeg的Go绑定,因为纯Go实现硬编码视频文件太大了。
// 调用FFmpeg合并音频视频
cmd := exec.Command("ffmpeg",
"-i", "video_temp.mp4",
"-i", "audio.mp3",
"-c:v", "copy",
"-c:a", "aac",
"final_video.mp4",
)
这个方法有点绕,但省去了自己实现编码器的麻烦。你如果不想装FFmpeg,可以试试github.com/3d0c/gmf这个库,但文档比较少,我当时没敢碰。
最终效果:有点粗糙,但很真实
你问值不值得?我花了两周下班时间,最后生成一个5分钟的视频,画面不是高清,声音偶尔对不上嘴型(也没人说话),但对象看完哭了,她说:“这些代码是你写的,每一帧都是你处理过的,比花钱找人做的有意义多了。”
其实最后输出的视频有点小毛病:第102帧的日期显示错位了,因为那天我用了一个很长的文件名,但我想想还是保留了,就像我们这一年,也不是每件事都完美。
你可以从这里开始
如果你想自己做一个类似的纪念视频,这是我的建议步骤——别想一步到位,先跑通流程:
- 准备素材:把照片按日期命名,整理到文件夹
- 写个简单的Go程序:只生成第一帧,看看字体和排版对不对
- 批量生成所有帧:注意内存管理,记得用
runtime.GC()回收 - 合成视频:先不要音频,看看帧率对不对
- 最后加音频——如果这一步搞不定,用剪辑软件手动加也行
别纠结于“必须全自动”,生活本身就是半成品加工。
一年前的今天,我在写第一行纪念视频的代码
2023年5月20号,我开始写这个项目,当时想着365天后能拿出一个东西,现在回头看,代码仓促,逻辑混乱,但每一帧都记录了我们真实的365天。
如果你也在考虑做点什么纪念你们的一周年,不妨试试图文结合:每天一张图,一段话,用Go的text/template模板生成,我甚至把聊天记录里的“早安”“晚安”提取出来,按时间轴穿插在视频里——这个用字符串匹配就能做,不需要深度学习。
最后想说,技术选型不重要,重要的是你愿意为那365天花时间。Go语言快是快,但慢下来整理回忆也挺好的。

发表评论