当前位置:首页 > 单站 > 正文

用Golang给在一起365纪念日视频加点烟火气

  • 单站
  • 2026-07-08 08:02:45
  • 284
摘要: 在一起365纪念日视频:用Golang给回忆写一段代码一年前的今天,你和她/他可能刚认识,或者刚决定在一起,那时候的你们,估计没...

在一起365纪念日视频:用Golang给回忆写一段代码

一年前的今天,你和她/他可能刚认识,或者刚决定在一起,那时候的你们,估计没想过时间会过得这么快,365天,说长不长,说短不短,但足够让两个人从陌生到熟悉,从试探到依赖,而当这个节点来临,很多人会想做点什么来纪念——比如一个“在一起365纪念日视频”。

我呢,是个爱折腾的Golang程序员,别人可能用剪映、PR、Final Cut Pro来剪片子,我想着:能不能用代码来生成这个视频?用Golang写一个程序,把这一年的照片、文字、音乐整合到一起,输出一个独一无二的纪念视频。听起来有点技术宅,但做出来的效果其实挺暖的。

第一步:准备素材——照片、文字、音乐

做视频之前,得先想好要放什么素材,我翻了翻手机相册,发现这一年的照片还真不少:第一次一起做饭、第一次吵架后和好的自拍、一起去看的日落、她/他睡着时我偷拍的表情……这些照片,每一张都能让我想起当天的天气、对方穿的衣服、说的话。

我决定用Golang的image来读取这些照片,再用ffmpeg把它们合成视频帧,Golang标准库里的image/jpegimage/png可以直接处理图片,但我需要控制每张照片的停留时长、转场效果、再加点文字字幕。

  • 照片列表:我写了一个photos.txt,每一行是照片路径和对应的时间戳。
  • :第1天:第一次见面”、“第100天:我们养了猫”、“第365天:有你真好”。
  • 背景音乐:挑了首我们都喜欢的歌,用os/exec调用ffmpeg混音。

说实话,这一步费了不少时间,因为照片尺寸不一样,有的横屏、有的竖屏,直接拼起来会拉伸变形,我写了个函数,把图片统一缩放到1920x1080,然后用黑色背景填充空白部分,效果还行,至少画面是统一的。

第二步:生成视频帧——Golang的image包实战

视频就是连续的图片,每秒24帧或30帧,我选了24帧,因为慢一点,适合纪念视频的节奏,但一张照片要停留多久?我定了3秒,也就是72帧(24帧/秒 * 3秒),这样50张照片,就是150秒,约2分半钟,不长不短。

代码逻辑大概是这样的:

for i, photo := range photoList {
    img := readImage(photo.Path)
    for frame := 0; frame < 72; frame++ {
        // 在图片上画文字
        drawText(img, photo.Text, time.Now())
        // 保存为帧图片
        saveFrame(img, i, frame)
    }
}

我用了golang.org/x/image/fontgolang.org/x/image/font/basicfont来在图片上写字,字体是默认的等宽字体,清晰度一般,但够用了,如果你想要更漂亮的字体,可以下载.ttf文件,用freetype库渲染。

这里有个坑:文字渲染的位置、大小、颜色都要调,我试了好多次,最后放在图片左下角,白色字体,带黑色描边,这样不管照片背景是什么颜色都能看清,描边的代码我参考了fogleman/gg这个库的思路,但其实用image/draw也能实现。

第三步:合成视频——用ffmpeg命令行

所有帧图片生成后,用ffmpeg把它们合成为视频文件,Golang里用os/exec执行命令行:

cmd := exec.Command("ffmpeg", "-framerate", "24", "-i", "frame_%d.png", "-c:v", "libx264", "-pix_fmt", "yuv420p", "output.mp4")
cmd.Run()

这个过程很慢,50张照片、3600帧(50*72),我的MacBook Pro跑了两分多钟,但看到生成的视频能正常播放时,那种成就感真的很难形容。

然后加背景音乐:

cmd = exec.Command("ffmpeg", "-i", "output.mp4", "-i", "music.mp3", "-c:v", "copy", "-c:a", "aac", "-shortest", "final_video.mp4")
cmd.Run()

这里要注意音频时长和视频时长匹配,我用了-shortest参数,如果音乐比视频长,它会自动截断;如果音乐短,视频末尾会静音,为了效果更好,我提前用Audacity把音乐剪到了2分30秒左右。

第四步:加特效和字幕——让视频更精致

纯图片切换的纪念视频有点单调,我加了简单的交叉淡入淡出效果,这个在ffmpeg里用-filter_complex实现:

ffmpeg -i input.mp4 -vf "fade=in:0:30,fade=out:last:30" output.mp4

但我不想全部淡入淡出,而是每张照片切换时淡入淡出,这个有点复杂,我最后用了mpv--vf参数做测试,然后写了个脚本批量处理每张照片的帧。

真正的转场效果其实没完全做出来,因为我时间有限,而且ffmpeg的滤镜语法我记不太清,最后我选择了“硬切”——就是直接切,每张照片切换时加一个0.1秒的白色闪光,模拟相机快门效果,这个实现简单:在切换的帧上画一个全白矩形,透明度逐渐降低。

字幕的话,我每张照片底部都写了日期和一句话,用draw.DrawMask把文字画上去,位置固定,字体大小14pt,颜色白色,有些照片文字被内容遮挡了,应该调整位置,但我没来得及改,就这样吧——不完美反而真实

第五步:导出和分享——把Golang生成的视频发给对方

最终视频是.mp4格式,用H.264编码,大部分设备都能播放,我把它传到百度网盘,把链接发给女朋友,备注:“用Golang写的纪念视频,你看一下。”

她看完后笑着说:“你们程序员表达爱的方式真特别。”我问她哪里特别,她说:“别人送花、送礼物,你送了一串代码的输出结果。”但我知道,她挺喜欢的,因为她说“每个日期和文字都对得上,你是不是翻了我朋友圈?”其实我是对照手机相册的时间戳写的,每条文字背后都有故事。

一些值得注意的细节和坑

环节 遇到的问题 解决办法
图片分辨率不统一 横图竖图混在一起,合成后变形 统一缩放至1920x1080,空白用黑色填充
文字被图片内容遮挡 白色字在天空背景下看不清 加黑色描边(draw.DrawMask两次)
音频时长不匹配 音乐比视频长或短 -shortest参数,或提前剪辑
帧图片过多,磁盘爆满 3600帧图片占了几百MB 合成后批量删除临时帧(os.Remove
字体不够美观 默认字体平淡无奇 下载开源字体如Source Han Serif

如果你也想尝试,建议先用10张照片测试流程。调试通过后再批量处理全部照片,否则生成几千帧图片后才发现错误,会很麻烦。

代码之外的思考:纪念的意义是什么

写这个程序花了我两个周末,第一个周末在解决图片缩放和文字渲染,第二个周末在调ffmpeg的转场效果,过程中我反复看那些照片,记住了一些差点忘记的细节:那张在路边摊吃烧烤的照片,是去年夏天,她辣到不停喝冰水;那张两人坐地铁的照片,是她靠在我肩膀上睡着了,我单手拍的。

有时候我觉得,这个视频不只是为了纪念“在一起365天”,更是为了提醒自己:时间虽然过去了,但那些瞬间还在,而用Golang来制作,只是我表达这些的一种方式。

后来我又想,如果明年纪念日,我是不是应该写一个更高级的版本:加弹幕动画、加背景音乐波形图、甚至是AR特效?但想想还是算了,这个版本虽然粗糙,现在”的产物,明年如果我变得更强了,那明年的视频也会更好,就这样一步步来,挺好的。

最后生成的那个“在一起365纪念日视频”,现在还在我手机里,有时候翻出来看,还是觉得——虽然代码写得不完美,但回忆挺完美的。

用Golang给在一起365纪念日视频加点烟火气