用Go语言搞定2周岁365天视频剪辑,这事我真干过
- 能源
- 2026-07-03 03:05:24
- 299
说实话,一开始我也觉得用Go语言做视频剪辑这事儿挺离谱的,毕竟大家都是用Adobe Premiere、Final Cut Pro,或者至少是FFmpeg命令行,但我女儿2周岁那天,我盯着手机里365天的零碎视频素材——整整30多个G,整个人都懵了。
手动剪?不可能,花钱请人剪?太贵,所以我干脆用Go写了个自动化剪辑脚本,结果还挺香,今天这篇东西,就是我踩坑后的真实记录。
为什么要用Go来剪视频?
你可能想问:Python不香吗?OpenCV不香吗?香,但Go有它自己的优势:
- 编译成单个二进制文件,丢到服务器或者树莓派上就能跑,不用装一堆依赖
- 并发处理能力强,Goroutine天生适合处理多个视频片段的并行转码
- 跨平台编译简单,Windows上写,Linux上跑,一行命令搞定
Go本身不直接处理视频,我们需要借助FFmpeg这个底层工具,说白了,Go负责逻辑编排,FFmpeg负责实际干活。
第一步:弄清楚2周岁365天视频要剪成啥样
我给自己定了几个规则,你可以参考:
| 需求 | 说明 |
|---|---|
| 每天最多保留2个精彩片段 | 避免素材太多选择困难 |
| 每个片段不超过30秒 | 保持节奏感 |
| 最终视频时长控制在10分钟以内 | 2周岁的孩子注意力就这么长 |
| 加上简单字幕和转场 | 稍微有点仪式感,不用太花哨 |
这个规划其实花了我整整一个下午,因为365天里有很多重复内容——吃饭、睡觉、哭、笑,你得挑出真正有记忆点的片段。
用Go调用FFmpeg:核心代码思路
最基础的调用方式
package main
import (
"fmt"
"os/exec"
)
func main() {
// 最简单的:把一段视频裁剪成30秒
cmd := exec.Command("ffmpeg",
"-i", "input.mp4",
"-t", "30",
"-c", "copy",
"output_30s.mp4")
err := cmd.Run()
if err != nil {
fmt.Println("失败了:", err)
}
}
这个小片段看起来简单,但实际跑起来你会发现一个问题:FFmpeg的参数顺序不能乱,参数写错一个位置,整个命令就崩了,我至少试了8次才调对参数。
用Goroutine并行处理多段视频
这是Go最爽的地方,假设你有365天的素材,每天提取2个片段,那就是730个片段要处理,串行跑,你得等到花儿都谢了。
func processVideo(input string, output string, duration int) {
cmd := exec.Command("ffmpeg",
"-i", input,
"-t", fmt.Sprintf("%d", duration),
"-c", "copy",
output)
cmd.Run()
}
// 用Goroutine并行处理
for _, video := range videoList {
go processVideo(video.Input, video.Output, 30)
}
不过这里有个坑:不要去开几百个Goroutine同时跑FFmpeg,你的CPU会炸,我一开始没控制,直接开了50个并行,结果电脑直接死机,后来加了信号量限制,最多同时跑4个,效果最好。
生成视频拼接列表
所有片段裁剪好以后,需要把它们拼成一条完整的视频,FFmpeg支持用一个文本文件来定义拼接顺序:
func generateConcatList(files []string) string {
var sb strings.Builder
for _, f := range files {
sb.WriteString(fmt.Sprintf("file '%s'\n", f))
}
return sb.String()
}
// 写入list.txt
listContent := generateConcatList(clippedFiles)
ioutil.WriteFile("list.txt", []byte(listContent), 0644)
// 执行拼接
cmd := exec.Command("ffmpeg",
"-f", "concat",
"-safe", "0",
"-i", "list.txt",
"-c", "copy",
"final_2years.mp4")
这一步容易出问题的地方是:不同片段的编码参数必须一致,否则拼接时会报错,解决办法是在裁剪时统一用相同的编码参数,比如都用H.264。
完整流程:从原始视频到成片
我整理了一下完整的工作流,照着做基本不会翻车:
-
素材整理
- 把365天的视频按日期分文件夹存储
- 手动选出每天最精彩的2-3个片段
- 用Excel或者CSV记录:文件名、开始时间、结束时间、备注
-
批量裁剪
- 用Go读取CSV文件
- 对每个条目执行FFmpeg裁剪命令
- 控制并发数在4-6个之间
-
生成字幕文件
- 根据CSV中的备注,生成SRT字幕文件
- 每个片段对应的字幕内容可以不同
-
拼接与渲染
- 所有片段拼接成一个完整视频
- 加上字幕
- 可选:调整整体亮度、对比度
我实际跑下来,30多个G的原始素材,最后产出了一部8分42秒的成片,文件大小只有800多MB。
遇到的坑,和怎么绕过去的
坑1:时间戳不对齐
有些视频的开始时间戳(PTS)不是从0开始的,导致裁剪出来的片段时间不准。
解决办法:在裁剪前加 -ss 和 -to 参数,并且用 -copyts 保持原始时间戳。
坑2:音频采样率不一致
手机拍的视频,有时候是44100Hz,有时候是48000Hz,拼接时音频会断断续续。
解决办法:统一用 -af "aresample=44100" 重新采样。
坑3:文件名字符编码问题
中文文件名在Windows上好好的,到了Linux上就乱码了。
解决办法:所有文件名都用纯数字+字母命名,实在要用中文,就存到CSV里,不要直接当文件名。
最终跑出来的结果,和一点小感受
视频剪完之后,我放给家里人看,我老婆看到第3分钟就哭了,不是因为技术多牛,而是那些差点被遗忘的瞬间——第一次走路摔跤、吃柠檬酸到皱眉、听到音乐扭屁股——全都被串起来了。
Go语言做这件事完全可行,甚至比我想象中更顺手,如果你也对剪辑不太感冒,又想把孩子的成长记录下来,用Go写个自动化脚本是一个很务实的选择。
代码我也没写得特别完美,有些地方甚至有点糙,但它跑起来了,有时候做东西就是这样,先让轮子转起来,再慢慢打磨。
