当前位置:首页 > 能源 > 正文

用Go语言搞定2周岁365天视频剪辑,这事我真干过

  • 能源
  • 2026-07-03 03:05:24
  • 299
摘要: 说实话,一开始我也觉得用Go语言做视频剪辑这事儿挺离谱的,毕竟大家都是用Adobe Premiere、Final Cut Pro...

说实话,一开始我也觉得用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。

完整流程:从原始视频到成片

我整理了一下完整的工作流,照着做基本不会翻车

  1. 素材整理

    • 把365天的视频按日期分文件夹存储
    • 手动选出每天最精彩的2-3个片段
    • 用Excel或者CSV记录:文件名、开始时间、结束时间、备注
  2. 批量裁剪

    • 用Go读取CSV文件
    • 对每个条目执行FFmpeg裁剪命令
    • 控制并发数在4-6个之间
  3. 生成字幕文件

    • 根据CSV中的备注,生成SRT字幕文件
    • 每个片段对应的字幕内容可以不同
  4. 拼接与渲染

    • 所有片段拼接成一个完整视频
    • 加上字幕
    • 可选:调整整体亮度、对比度

我实际跑下来,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写个自动化脚本是一个很务实的选择。

代码我也没写得特别完美,有些地方甚至有点糙,但它跑起来了,有时候做东西就是这样,先让轮子转起来,再慢慢打磨。

用Go语言搞定2周岁365天视频剪辑,这事我真干过