1. 项目缘起与整体思路拆解
1.1 为什么三个人的小团队要自己搭视频流水线
先说背景。我们团队一共三个人,一个负责脚本和选题,一个负责剪辑和运营,我负责技术。日常要产出短视频内容,每周大概五到八条,时长在一到三分钟之间。一开始我们试过外包剪辑,一条报价从八十到三百不等,质量参差不齐,改稿来回沟通的时间成本比自己做还高。后来也试过几个在线剪辑平台,模板化严重,批量生产时导出排队、水印、分辨率限制这些问题一个接一个。
真正让我们下决心自己搭流水线的触发点,是发现视频生产里大量环节其实是重复劳动:配音、字幕、片头片尾拼接、格式转换、封面截取。这些活儿不需要创意,但特别吃时间。如果能把它们串成一条自动化管道,人只需要做最核心的脚本和素材筛选,效率能翻好几倍。
关键约束是:我们没有任何独立显卡。三台机器都是普通的办公本,集成显卡,内存十六个G。这意味着本地跑视频生成模型、跑语音合成模型基本不现实。所以路线从一开始就很明确——用官方API做智能部分,用开源工具做机械部分,本地只负责调度和拼接。
1.2 整体架构:API负责“想”,开源工具负责“干”
整条流水线的逻辑可以用一句话概括:脚本进来,成片出去,中间所有需要“智能”的环节走API,所有需要“搬砖”的环节走本地开源工具。
具体拆成几个阶段。第一阶段是文案处理,把原始脚本整理成适合口播的文本,同时生成分镜描述。这一步用大模型的对话API完成,因为需要理解语义、调整语气、控制字数。第二阶段是语音合成,把口播文本转成音频,用的是 edge-tts 这个开源工具,它背后调用的是微软的在线语音服务,但通过开源库封装,使用起来非常轻量。第三阶段是素材匹配和拼接,根据分镜描述从本地素材库里挑视频片段,用 ffmpeg 做裁剪、拼接、变速。第四阶段是字幕生成和烧录,同样用 ffmpeg 配合语音识别的时间戳来完成。第五阶段是导出和分发,统一转成目标平台需要的分辨率和码率。
这套架构最大的好处是解耦。每个环节都是独立的命令行工具或API调用,任何一个环节出问题,不影响其他环节。而且所有中间产物都是标准格式的文件——文本、wav、mp4、srt,方便排查和替换。
1.3 为什么选 edge-tts 和 ffmpeg 这两个核心工具
语音合成这块,我们对比过几个方案。商业API按字符收费,一条三分钟的视频大概要几百到上千字,成本虽然不算高,但量大了也是钱。本地开源方案像一些基于深度学习的TTS,效果确实好,但需要显卡,我们跑不动。edge-tts 刚好卡在中间:它调用的是在线服务,但通过开源库访问,不需要密钥,音色选择多,中文效果自然,而且生成速度很快,一条三分钟的口播音频大概十几秒就出来了。
ffmpeg 就更不用说了,视频处理领域的瑞士军刀。裁剪、拼接、转码、加字幕、调分辨率、抽帧、混音,几乎没有它干不了的。而且它是命令行工具,特别适合脚本化调用。我们整条流水线里,ffmpeg 出现的频率最高,几乎每个环节都有它。
提示:edge-tts 生成的是 mp3 格式,后续用 ffmpeg 处理时要注意采样率和声道数的统一,否则拼接时容易出现音画不同步。
1.4 这套方案适合谁参考
如果你也是小团队或者个人创作者,没有独立显卡,但想批量生产口播类、解说类、知识分享类的视频,这套方案可以直接抄作业。它不适合需要复杂特效、实拍剪辑、精细调色的场景,但对于“文本转视频”这个大类目,覆盖度已经足够。前提是你得会一点命令行,能看懂 Python 脚本,遇到报错知道去查日志。完全零基础的话,建议先花半天时间熟悉 ffmpeg 的基本命令,再上手整条流水线。
2. 核心环节拆解与实操要点
2.1 文案处理:用大模型API把脚本变成口播稿加分镜表
原始脚本往往是一篇结构化的文章,直接念出来会很生硬。我们的做法是写一个提示词模板,让大模型输出两部分内容:一部分是口播稿,要求口语化、短句为主、每句不超过二十个字;另一部分是分镜表,用 JSON 格式返回,每个分镜包含序号、画面描述、对应口播稿的起止句子。
提示词的关键在于约束输出格式。我们试过让模型自由发挥,结果每次返回的结构都不一样,解析起来很痛苦。后来改成强制 JSON 输出,并且在提示词里给出一个示例结构,稳定性大幅提升。另外要注意控制总字数,三分钟的视频口播稿大概在七百到九百字之间,太长了配音会赶,太短了画面会空。
调用API时,我们用的是流式输出,边生成边解析,这样等待时间短一些。错误处理也很重要,网络超时或者返回格式不对时要有重试机制。我们设了三次重试,每次间隔两秒,基本能覆盖大部分偶发问题。
注意:不同的大模型API对 JSON 模式的支持程度不一样,有的需要额外参数开启,有的对嵌套层级有限制。建议先用小样本测试,确认返回结构稳定后再批量跑。
2.2 语音合成:edge-tts 的参数调优与批量生成
edge-tts 的命令行用法很简单,一行命令就能把文本转成音频。但实际用起来有几个坑。第一个是语速,默认语速偏快,中文口播听起来有点赶。我们通过 rate 参数调到 -10% 左右,听起来更自然。第二个是音色选择,中文推荐用云希或者晓晓,前者偏男声沉稳,后者偏女声亲和,根据内容调性选。第三个是标点处理,edge-tts 对逗号和句号的停顿处理不一样,我们会在文本预处理阶段把长句拆短,用句号代替逗号,停顿感更好。
批量生成时,我们写了一个 Python 脚本,读取分镜表里的口播稿,按段落切分,逐段生成音频文件,最后用 ffmpeg 拼接成一个完整的音轨。这里要注意段落之间的静音间隔,太短了听起来急促,太长了又拖沓。我们实测下来,段间静音设为零点三秒比较合适。
还有一个细节是音频的采样率。edge-tts 默认输出 24kHz 的 mp3,而后续视频素材的音频通常是 44.1kHz 或 48kHz。如果不统一,拼接时 ffmpeg 会自动重采样,但偶尔会出现爆音。我们的做法是在生成阶段就用 ffmpeg 转成 48kHz 的 wav,后续处理全部基于这个格式。
2.3 素材匹配:根据分镜描述从本地库挑片段
素材库是我们平时积累的,按标签分类,比如“城市夜景”“办公场景”“数据图表”“自然风景”等。分镜表里的画面描述会包含关键词,我们写了一个简单的匹配脚本,用关键词去素材库的标签里找,找到就选,找不到就用默认的填充素材。
匹配逻辑不复杂,但有几个经验点。第一,同一个素材不要连续用两次,否则观众会看出来。我们在脚本里加了去重逻辑,记录最近用过的素材ID,优先选没用过的。第二,素材的时长要略长于口播稿对应段落的时长,方便裁剪。第三,横屏和竖屏素材要分开管理,最终输出是竖屏的话,横屏素材需要做模糊背景填充或者裁剪,这个在 ffmpeg 里用 crop 和 scale 滤镜组合实现。
2.4 视频拼接与字幕烧录:ffmpeg 滤镜链的实战配置
这是整条流水线里最技术性的部分。我们的做法是先用 ffmpeg 把每个分镜对应的视频片段裁剪到目标时长,统一分辨率和帧率,然后拼接成一个完整的视频轨。接着把音轨和视频轨合并,最后烧录字幕。
裁剪命令的核心是 -ss 和 -t 参数,分别指定起始时间和持续时长。这里要注意 -ss 放在 -i 前面还是后面,放在前面是快速定位但可能不精确,放在后面是精确裁剪但速度慢。我们实测下来,对于短视频片段,放在前面加 -accurate_seek 参数,精度足够。
拼接用的是 concat 协议,需要先把所有片段转成相同的编码格式和分辨率,否则会报错。我们统一转成 H.264 编码、1920x1080 分辨率、30帧每秒、yuv420p 像素格式。这一步虽然多花点时间,但能避免后面各种奇怪的兼容问题。
字幕烧录用的是 subtitles 滤镜,需要先把 srt 文件准备好。srt 的时间戳可以从 edge-tts 生成音频时同步获取,也可以用语音识别工具反向生成。我们用的是前者,因为 edge-tts 在生成音频时会输出每个词的边界时间,解析后就能得到精确的字幕时间轴。
提示:ffmpeg 的 subtitles 滤镜对字体和编码有要求,中文建议用思源黑体或微软雅黑,srt 文件保存为 UTF-8 编码,否则会出现乱码。
3. 完整实操流程与关键步骤实现
3.1 环境准备:三台普通办公本的软件配置
我们的三台机器都是 Windows 系统,配置是 i5 处理器、16G 内存、集成显卡。软件层面需要装的东西不多:Python 3.10 以上、ffmpeg 可执行文件、edge-tts 库、requests 库用于调API。ffmpeg 建议下载官方编译的静态版本,解压后把 bin 目录加到系统环境变量里,这样在任何路径下都能直接调用。
Python 环境我们用 venv 建了虚拟环境,避免依赖冲突。edge-tts 用 pip 安装,命令是pip install edge-tts。安装完成后可以用edge-tts --list-voices查看可用音色,确认中文音色存在。
API 密钥统一放在一个配置文件里,用环境变量读取,不要硬编码在脚本里。我们用的是 dotenv 库,把密钥写在 .env 文件里,脚本启动时加载。这样既安全,也方便在不同机器之间同步配置。
3.2 从脚本到分镜表:一次完整的API调用记录
假设我们有一篇八百字的文章,要转成三分钟的视频。第一步是把文章和提示词一起发给大模型。提示词大概是这样:你是一个短视频口播稿撰写助手,请把以下文章改写成口语化的口播稿,要求每句不超过二十字,总字数控制在七百到九百字之间。同时输出分镜表,JSON格式,每个分镜包含序号、画面关键词、对应口播稿的句子范围。
发送请求后,模型返回的内容我们解析出两部分。口播稿按句号切分,得到大概四十到五十个句子。分镜表大概十到十五个分镜,每个分镜对应三到五个句子。这里要注意,模型返回的 JSON 偶尔会有格式错误,比如多了一个逗号或者少了引号。我们的处理方式是先用正则提取 JSON 部分,再用 json.loads 解析,失败的话就重试或者手动修。
调用记录显示,一次完整的生成大概需要十五到三十秒,取决于模型负载。我们用的是按量付费的API,成本大概每条视频几毛钱,完全可以接受。
3.3 音频生成与时间轴提取:edge-tts 的进阶用法
edge-tts 的 Python 库提供了更细粒度的控制。我们用的是Communicate类,可以指定音色、语速、音量,还能获取每个词的边界时间。代码大概是这样:
import edge_tts import asyncio async def generate_audio(text, voice, rate, output_path): communicate = edge_tts.Communicate(text, voice, rate=rate) with open(output_path, "wb") as f: async for chunk in communicate.stream(): if chunk["type"] == "audio": f.write(chunk["data"]) elif chunk["type"] == "WordBoundary": # 记录词边界时间 pass实际使用时,我们把每个分镜的口播稿单独生成一个音频文件,同时记录该分镜的起始时间。所有分镜生成完后,用 ffmpeg 按顺序拼接,拼接时在每个片段之间插入零点三秒的静音。拼接命令用 concat 协议,先写一个列表文件,每行是file '片段路径',然后执行ffmpeg -f concat -safe 0 -i list.txt -c copy output.wav。
时间轴方面,我们不需要精确到词,只需要每个分镜的起止时间。这个可以从拼接时的累计时长算出来。有了分镜时间轴,字幕的时间戳也就有了。
3.4 视频轨组装:裁剪、缩放、拼接的完整命令
视频轨的组装分三步。第一步是裁剪,把每个素材片段裁到目标时长。命令是:
ffmpeg -ss 00:00:05 -t 00:00:12 -i source.mp4 -c:v libx264 -preset fast -crf 23 -r 30 -s 1920x1080 -pix_fmt yuv420p -an clip_01.mp4这里 -ss 指定从第5秒开始,-t 指定持续12秒,-an 表示去掉音频(音频后面单独处理),-r 30 统一帧率,-s 统一分辨率。
第二步是拼接,把所有 clip 文件按顺序拼成一个视频轨:
ffmpeg -f concat -safe 0 -i video_list.txt -c copy video_track.mp4第三步是合并音视频:
ffmpeg -i video_track.mp4 -i audio_track.wav -c:v copy -c:a aac -b:a 192k -shortest final_no_sub.mp4-shortest 参数确保输出时长以较短的流为准,避免音视频长度不一致导致的黑屏。
3.5 字幕烧录与最终导出:一步到位的命令模板
字幕烧录用 subtitles 滤镜,命令是:
ffmpeg -i final_no_sub.mp4 -vf "subtitles=subtitle.srt:force_style='FontName=Microsoft YaHei,FontSize=18,PrimaryColour=&HFFFFFF,OutlineColour=&H000000,Outline=2'" -c:a copy final_with_sub.mp4force_style 里可以调字体、字号、颜色、描边。我们实测下来,字号18、白色字、黑色描边2像素,在手机上看很清楚。
最终导出时,根据目标平台调整码率。竖屏平台一般要求 1080x1920 分辨率,码率 4M 到 6M。横屏平台 1920x1080,码率 8M 到 10M。命令里加 -b:v 参数控制码率,-maxrate 和 -bufsize 控制码率波动。
整个流程从脚本到成片,熟练之后大概十五到二十分钟一条,其中大部分时间是机器在跑,人只需要在关键节点检查一下。
4. 常见问题与排查技巧实录
4.1 音频与视频时长不匹配的三种原因
这是最常见的问题。第一种原因是音频拼接时的静音间隔没算准,导致总时长比视频轨长或短。解决办法是在拼接音频时记录实际总时长,然后调整视频轨的最后一个片段时长来对齐。第二种原因是视频片段裁剪时用了不精确的 -ss 参数,导致实际时长有偏差。解决办法是裁剪后用 ffprobe 检查实际时长,必要时重新裁剪。第三种原因是编码时的帧率不一致,导致播放时音画不同步。解决办法是全程统一帧率,不要混用。
4.2 edge-tts 生成失败或音色不可用的处理
edge-tts 依赖在线服务,偶尔会遇到网络波动导致生成失败。我们的处理方式是加超时和重试,单次生成超过三十秒就中断重试,最多三次。如果连续失败,就切换到备用音色。另外,edge-tts 的音色列表会更新,有些音色可能被下线。建议在脚本启动时先拉取一次音色列表,确认目标音色存在。
还有一个坑是文本里的特殊字符。比如引号、括号、emoji,edge-tts 处理时可能会出错或者跳过。我们的做法是在文本预处理阶段把这些字符替换成空格或者对应的文字描述。
4.3 ffmpeg 拼接报错的排查思路
拼接报错最常见的原因是片段之间的编码参数不一致。比如有的片段是 H.264,有的是 H.265,有的帧率是 25,有的是 30。解决办法是拼接前统一转码,用同一套参数重新编码所有片段。虽然多花时间,但能避免绝大多数问题。
另一个原因是 concat 列表文件的路径问题。路径里有空格或中文时,需要用单引号包裹,并且加 -safe 0 参数。如果路径是相对路径,要确保执行命令时的工作目录正确。
还有一个隐蔽的问题是音频采样率不一致。视频片段如果没有音频轨,拼接时不会报错,但合并音视频时可能会出问题。我们的做法是视频片段一律去掉音频轨,音频单独处理,这样最干净。
4.4 字幕乱码与时间轴偏移的修正方法
字幕乱码通常是编码问题。srt 文件必须保存为 UTF-8 无 BOM 格式,否则 ffmpeg 解析时会乱码。另外,字体名称要用系统里实际安装的字体名,不能随便写。Windows 下可以用fc-list命令查看已安装字体,或者直接在字体设置里看。
时间轴偏移一般是音频拼接时的累计误差导致的。我们的做法是在生成字幕后,用 ffmpeg 的 -itsoffset 参数整体平移字幕时间,或者手动调整 srt 文件里的时间戳。更彻底的办法是在音频拼接阶段就用精确的时长计算,避免误差累积。
4.5 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 音画不同步 | 帧率不一致或时长计算误差 | 用 ffprobe 检查各片段时长和帧率 | 统一帧率,重新计算时长 |
| 拼接报错 | 编码参数不一致 | 检查各片段的编码格式 | 统一转码后再拼接 |
| 字幕乱码 | 编码或字体问题 | 检查 srt 编码和字体名称 | 转 UTF-8,用系统字体 |
| 语音生成失败 | 网络波动或音色下线 | 查看错误日志,检查音色列表 | 重试或切换音色 |
| 导出文件过大 | 码率设置过高 | 检查 -b:v 参数 | 降低码率或改用 CRF 模式 |
| 视频黑屏 | 像素格式不支持 | 检查 -pix_fmt 参数 | 统一用 yuv420p |
4.6 几个踩过坑之后总结的实操心得
第一个心得是中间产物全部保留。我们一开始为了省磁盘空间,生成完就删中间文件,结果出问题时没法排查,只能从头跑一遍。后来改成所有中间文件保留至少一周,排查效率大幅提升。
第二个心得是参数配置化。分辨率、码率、语速、静音间隔这些参数,全部写在配置文件里,不要硬编码在脚本里。这样换平台或者调风格时,改一个文件就行,不用翻代码。
第三个心得是日志要详细。每个环节的开始时间、结束时间、输入输出文件、关键参数,全部记到日志里。出问题时看日志就能定位到具体环节,不用瞎猜。
第四个心得是先跑通再优化。一开始不要追求完美,先用最简单的参数跑通整条流程,哪怕画质一般、字幕位置不对,先让流程能走通。然后再逐个环节调优,这样心理压力小,也更容易坚持下来。
注意:ffmpeg 的版本更新比较快,不同版本对某些滤镜的支持程度不一样。建议锁定一个稳定版本,不要频繁升级,避免脚本突然跑不通。
5. 成本、效率与后续扩展的实测数据
5.1 单条视频的时间与费用拆解
我们统计了最近二十条视频的生产数据。平均每条视频时长两分半,口播稿八百字左右。API调用费用大概三到五毛钱,主要是文案处理和分镜生成。edge-tts 免费,ffmpeg 免费。时间方面,文案处理加API调用大概一分钟,语音合成三十秒,素材匹配和裁剪两分钟,拼接和字幕三分钟,导出两分钟。总计大概八到十分钟,其中人工干预时间不超过三分钟。
对比外包剪辑,单条成本从一百多降到几毛钱,时间从半天降到十分钟。当然,我们的视频类型比较标准化,如果是复杂剪辑,这套流水线就不适用了。
5.2 批量生产的调度策略
我们不是一条一条跑,而是攒一批脚本,晚上统一跑。写一个主控脚本,遍历所有待处理的脚本文件,依次执行各个阶段。跑的时候机器占用不高,可以同时做别的事情。第二天早上检查成片,微调后发布。
批量跑的时候要注意磁盘空间和内存占用。ffmpeg 转码比较吃CPU,三台机器同时跑的话,建议错开时间,或者限制并发数。我们设的是同时最多跑两条,基本不影响日常使用。
5.3 后续可以扩展的方向
这套流水线目前覆盖的是口播类视频,后续可以扩展的方向有几个。一是加入自动封面生成,从视频里抽帧加标题文字,用 ffmpeg 的 drawtext 滤镜实现。二是加入背景音乐自动混音,根据视频情绪从音乐库里选曲,用 ffmpeg 的 amix 滤镜混合。三是加入多语言版本,用 edge-tts 的其他语言音色生成不同语种的音轨,视频轨复用。
还有一个方向是把整条流水线容器化,用 Docker 打包,这样换机器或者多人协作时,环境配置一键搞定。不过我们目前三台机器配置一样,暂时没这个需求。
5.4 我个人在实际操作中的体会
这套方案最大的价值不是技术多先进,而是把重复劳动自动化了。三个人小团队,最缺的就是时间。以前剪辑师一天只能出一条,现在一天能出五条,而且质量稳定。技术门槛其实不高,会一点 Python 和命令行就能搭起来。关键是愿意花半天时间踩坑,把流程跑通。
踩过的最大坑是 ffmpeg 的参数兼容性。不同版本、不同编码格式、不同平台,参数行为可能不一样。我的建议是锁定一套参数,跑通之后就不要随便改。遇到问题先看日志,日志里通常有明确的错误提示。实在搞不定就去查 ffmpeg 的官方文档,或者用 ffprobe 分析文件的具体参数,对症下药。
最后再分享一个小技巧:edge-tts 生成音频时,可以同时输出字幕文件。虽然格式需要转换,但比用语音识别反向生成要准确得多。这个功能在文档里不太显眼,但实测下来非常实用。