0.2 跑通最小流水线


0.2 跑通最小流水线

本节摘要:本节把 0.1 节的七段骨架缩成一条能跑的最小闭环。环境只要两样:Python 3.10 以上与 ffmpeg,外加 Pillow 画图。然后写一个三十余行的脚本:两段文字先用 Pillow 画成两张 1280 by 720 的字卡,再由 ffmpeg 的 concat 清单拼成各 2.5 秒的两镜,字幕用 SRT 文件烧录进画面,输出一条带字幕的五秒成片——全程本地完成,不依赖任何付费 API。跑通之后,本节给出「替换路线图」:最小闭环里的每个占位实现,在完整流水线里对应的真身是哪一节的哪个模块。0.1 节负责「看得懂」,本节负责「跑得通」。

学习目标

  • 装好 Python、ffmpeg 与 Pillow,并通过三条自检命令验证。
  • 说清最小闭环里每个步骤对应七段加工里的哪一段。
  • 独立跑通「两段文字到五秒成片加字幕」,并排查三类常见故障。
  • 拿着替换路线图,知道下一步把哪个占位换成真模块。

一、环境准备

全书的运行环境刻意保持朴素:Python 加 ffmpeg,没有重量级框架。组件清单如下:

组件 版本口径 用途 服务章节
Python 3.10 以上 流水线各段的胶水语言 全书
ffmpeg 6.x(以官网为准) 拼接、转码、字幕烧录 第 0、5 章
Pillow 10.x 以上 生成字卡图片 本节
moviepy 2.x(以官方文档为准) Python 剪辑 第 5 章

安装与自检(Windows 读者在 Git Bash 里执行;ffmpeg 若未入 PATH,到 ffmpeg 官网下载后把 bin 目录加进 PATH):

# bash —— 环境安装与自检 python -m pip install pillow python --version # 建议 3.10 以上 ffmpeg -version # 能打印版本即已安装 python -c "import PIL; print(PIL.__version__)" ​

四条命令都通过,环境就绪。本节不需要任何模型 API 密钥——这是刻意的设计:最小闭环的意义是验证「管线通」而不是「模型好」。

二、最小闭环的设计

把七段加工压缩到一次能看完的规模:

两段文字 ──▶ [脚本段] 剧本清单(写死在代码里) │ ▼ 两张字卡 ──▶ [素材+生成段] Pillow 画图(占位:将来换成文生图/文生视频) │ ▼ concat 清单 ─▶ [剪辑段] ffmpeg 拼接(占位:将来换成 moviepy 时间线) │ ▼ 两行 SRT ───▶ [字幕段] 烧录进画面(占位:将来换成 Whisper 对齐) │ ▼ final.mp4 ──▶ [导出段] 五秒、30 帧、H.264 ​

音轨段在最小闭环里缺席(无声成片),后半本第 6 章补齐。每个占位实现将来替换成哪个真模块,本节末尾给路线图。

三、代码实现

一个文件,四十行以内:

# min_pipeline.py —— 最小流水线:两段文字、两张图、一条五秒成片(本地零 API 依赖) import subprocess from pathlib import Path from PIL import Image, ImageDraw, ImageFont WORK = Path("build") WORK.mkdir(exist_ok=True) FONT = "C:/Windows/Fonts/msyh.ttc" # macOS 可换成系统自带的中文字体路径 SEGMENTS = [ ("一句想法", "流水线的输入端"), ("一条成片", "流水线的输出端"), ] def make_frame(title, note, index): img = Image.new("RGB", (1280, 720), (24, 26, 32)) pen = ImageDraw.Draw(img) big = ImageFont.truetype(FONT, 96) small = ImageFont.truetype(FONT, 44) pen.text((640, 300), title, font=big, fill=(235, 235, 240), anchor="mm") pen.text((640, 470), note, font=small, fill=(140, 200, 255), anchor="mm") out = WORK / ("frame_%02d.png" % index) img.save(out) return out.as_posix() frames = [make_frame(title, note, i) for i, (title, note) in enumerate(SEGMENTS)] entries = [] for item in frames: entries.append("file '%s'\nduration 2.5\n" % item) entries.append("file '%s'\n" % frames[-1]) # concat 清单的已知细节:末帧需重复一次文件行 list_file = WORK / "list.txt" list_file.write_text("".join(entries), encoding="utf-8") srt_text = ( "1\n00:00:00,000 --> 00:00:02,500\n一句想法\n\n" "2\n00:00:02,500 --> 00:00:05,000\n一条成片\n\n" ) (WORK / "subs.srt").write_text(srt_text, encoding="utf-8") subprocess.run( [ "ffmpeg", "-y", "-f", "concat", "-safe", "0", "-i", "list.txt", "-vf", "subtitles=subs.srt", "-r", "30", "final.mp4", ], check=True, cwd=WORK, ) print("成片已生成:", (WORK / "final.mp4").resolve()) ​

三处值得停下来看的设计。其一,段间以文件为契约:字卡是 png 文件,拼接依据是 list.txt,字幕是 subs.srt,段与段之间不传内存状态——这就是 0.1 节「七段以文件衔接」的缩微版。其二,字幕走标准格式:SRT 是字幕段的通用语言,烧录滤镜一条命令完成,将来换成 Whisper 生成的 SRT,这一行不用改。其三,ffmpeg 在产物目录内以相对路径运行(cwd 参数),避开 Windows 盘符冒号在滤镜参数里的转义坑。

四、运行与验收

# bash —— 运行最小流水线并验收产物 python min_pipeline.py ls build # 应看到 frame_00.png、frame_01.png、list.txt、subs.srt、final.mp4 ffprobe -v error -show_entries format=duration -of csv=p=0 build/final.mp4 ​

验收标准:final.mp4 存在,时长约 5 秒,播放可见两张字卡各 2.5 秒,底部字幕按时间码切换。常见故障三类:

症状 原因 处置
ffmpeg 不是内部或外部命令 未安装或未入 PATH 官网下载后把 bin 目录加入 PATH,重开终端
报错 OSError cannot open font 字体路径不对 换成本机存在的中文字体文件路径
字幕乱码或不出 SRT 编码或字体缺字形 确认 SRT 以 UTF-8 写出、字体含中文字形

五、从最小到完整:替换路线图

最小闭环的价值在于它把每个占位实现的位置标清楚了。往完整流水线走,逐个替换:

最小闭环里的占位 完整流水线里的真身 落在
写死在代码里的两段文字 LLM 结构化生成的剧本 JSON 第 2.1 节
Pillow 画的两张字卡 文生图 API 或素材库取图,再经图生视频成片段 第 3、4 章
concat 拼两镜 分镜 JSON 驱动的 moviepy 时间线 第 5.2 节
手写的两行 SRT Whisper 逐镜对齐自动生成 第 7 章(后半本)
无声成片 TTS 配音、音效与混音 第 6 章(后半本)
手工敲一条命令 Agent 编排的一条命令全流程 第 8 章(后半本)

替换的次序建议按「素材与生成 → 剪辑 → 字幕 → 音轨」推进:先把画面的来源换成真模型(质量收益最大),再让剪辑吃上分镜 JSON,字幕与音轨随后。每替换一段,其余段不动——这条纪律在下一章升级为总论。

本节要点回顾

  • 环境两件套:Python 加 ffmpeg,Pillow 本节专用,全部自检命令可复制运行。
  • 最小闭环七步走:文字、字卡、清单、拼接、字幕、烧录、成片,四十行以内跑通。
  • 段间以文件为契约、字幕走 SRT 标准、ffmpeg 用相对路径,三条设计贯穿全书。
  • 替换路线图把每个占位实现指回后续章节,替换次序按质量收益排。

闭环跑通只是「能跑」,下一章回答「怎么跑得不散」——契约怎么定、目录怎么摆、失败怎么只重跑那一段。

作者与出处
原作者:灏天文库
整理人: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U