video_maker1.0踩坑全记录

文章目录

项目目标

输入几张有序图片 + 每张图的字幕 + 背景音乐 → 输出竖屏短视频(1160×2112),带 AI 配音和字幕叠加。

GitHubhttps://github.com/guanlinyi/video-maker

最终效果

  • ✅ 图片自动缩放裁剪为竖屏(1160×2112)
  • ✅ 每张图显示时长 = 对应配音时长,说完自动切
  • ✅ 声音克隆:用一段 15 秒录音克隆出任意文字的语音
  • ✅ 字幕叠加:半透明黑底 + 白色文字
  • ✅ 背景音乐:从原视频中分离出来的纯音乐
  • ✅ 交叉淡入淡出转场
  • ✅ GPU 硬件编码,渲染速度快(12s 视频 ≈ 20s 渲染)
  • ⚠️ 配音偶尔有轻微的"诶"声(GPT-SoVITS 零样本生成的通病)

整体架构

复制代码
                    ┌─────────────────────┐
                    │     input/          │
                    │  图片 + 字幕 + BGM   │
                    └──────┬──────────────┘
                           │
              ┌────────────┴────────────┐
              │                         │
              ▼                         ▼
   ┌────────────────────┐   ┌──────────────────────┐
   │   GPT-SoVITS       │   │   ffmpeg             │
   │   声音克隆引擎      │   │   视频渲染引擎        │
   │                    │   │                      │
   │  输入: 文字+参考音频 │   │  filter_complex:     │
   │  输出: wav 语音文件  │   │  缩放图片→加字幕     │
   └────────┬───────────┘   │  →xfade转场→mix音频  │
            │               │                      │
            ▼               │  NVENC: GPU硬件编码   │
     ┌──────────────┐       │  输出 MP4            │
     │  .tts_cache/ │       └──────────────────────┘
     │  TTS 缓存    │               ▲
     └──────────────┘               │
                                    │
                          ┌─────────┴──────────┐
                          │   Demucs (PyTorch)   │
                          │   AI 音频分离模型     │
                          │                     │
                          │   原视频 → 人声+音乐  │
                          │   (bass+drums+other  │
                          │    混合成背景音乐)    │
                          └─────────────────────┘

术语解释

  • ffmpeg filter_complex:ffmpeg 提供的一种"滤镜图"功能,可以把多个视频/音频处理步骤串联起来。这里用它把图片缩放→叠加字幕→交叉淡入淡出→混合音频,全部一步完成,不需要中间文件。
  • NVENC:NVIDIA 显卡自带的硬件视频编码器。用它能比用 CPU 编码快 5-10 倍,而且渲染时不占用 CPU。
  • Demucs:Meta(Facebook)开源的 AI 音频分离模型。它能把一首歌里的人声、鼓声、贝斯、其他乐器分别提取出来。这里用它将原视频的人声和背景音乐分开。
  • xfade:ffmpeg 的交叉淡入淡出滤镜,让两张图之间平滑过渡。
  • amix:ffmpeg 的音频混合滤镜,把多路音频叠在一起。
  • dynaudnorm:动态音量归一化,让整段音频的音量保持平稳。

方案选择历程

方案一:edge-tts(在线配音)+ MoviePy 渲染

选了它因为:最简单,pip install 就能跑,不需要 GPU,不需要下载模型。

结果:能用,但:

  • 必须联网(走代理访问微软服务器)
  • 微软晓晓的 AI 女声不够自然
  • MoviePy 渲染 1160×2112 大分辨率视频极慢(38s 视频要 3.5 分钟)

方案二:CosyVoice 2.0(阿里通义,离线声音克隆)

选了它因为:号称中文零样本 TTS 最强,2 秒音频就能克隆声音,全离线。

GitHubhttps://github.com/FunAudioLLM/CosyVoice

论文https://arxiv.org/abs/2412.10117

模型下载https://www.modelscope.cn/models/iic/CosyVoice2-0.5B

结果:模型下载成功但推理废了(详见坑 2)。

方案三:GPT-SoVITS(最终方案)

GitHubhttps://github.com/RVC-Boss/GPT-SoVITS

Stars :58.4k,社区非常活跃

模型下载https://huggingface.co/lj1995/GPT-SoVITS

选了它因为

  • 对 PyTorch 新版兼容性好
  • 中文效果公认最好
  • 4060 Ti 实测 RTF 0.028(比实时快 35 倍)
  • 零样本 5 秒音频就能克隆
  • 也有 v3/v4 但 v2Pro 综合效果最好

踩坑记录


坑 1:模型下载极慢

问题:多个模型(CosyVoice2 ~4.5GB、GPT-SoVITS ~5GB)下载速度很慢。

根因:身处国内网络环境,pip/modelscope/huggingface 下载大文件需要走代理,速度仅 200KB/s-3MB/s 不等,且工具 timeout 频繁中断。

流程

复制代码
下载命令 → 开始下载 → 30分钟后被 timeout 杀死 → 手动重跑续传 → 循环 3-4 次

实际的操作步骤

bash 复制代码
# ❌ 不要这样下(太慢)
python -c "from modelscope import snapshot_download; snapshot_download('iic/CosyVoice2-0.5B', ...)"

# ✅ 正确方式:用 run_background + wait_for_job 轮询
python -c "from modelscope import snapshot_download; ..."  # 会超时但续传

# ✅ 最快方式:让用户浏览器自己下
# 打开 https://www.modelscope.cn/models/iic/CosyVoice2-0.5B
# 浏览器下载 3 分钟顶工具 3 小时

最终解决 :用 run_background 后台跑 + wait_for_job 以 10 分钟超时轮询。每次被杀死后重跑会续传,累积 3-4 次后下载完成。

教训:超过 100MB 的大文件,优先让用户用浏览器自己下载(快 100 倍)。


坑 2:CosyVoice2 和 PyTorch 2.9.0 不兼容

问题:模型加载成功,但推理输出 20-40 秒废音频。

根因 :CosyVoice2 官方基于 PyTorch 2.3.1 开发,其推理代码使用 torch.cuda.amp.autocast()。在 PyTorch 2.9.0 中,这个 API 的行为变了(虽然还没完全删除),导致模型生成完全错误的 token 序列。

尝试的修复

python 复制代码
# 尝试 1:禁用混合精度 --- 没用
cosyvoice = AutoModel(..., fp16=False)

# 尝试 2:手动改 model.py 用新版 API --- 没用
torch.amp.autocast('cuda', enabled=self.fp16, dtype=torch.bfloat16)

最终解决:放弃 CosyVoice2,换 GPT-SoVITS。

识别方法 :推理时日志显示 yield speech len 20.0(短句产出 20 秒音频),且音量极低,说明模型没正确停止生成。


坑 3:GPT-SoVITS 安装踩坑

GitHubhttps://github.com/RVC-Boss/GPT-SoVITS

官方安装步骤

bash 复制代码
conda create -n GPTSoVits python=3.10
conda activate GPTSoVits
pip install -r requirements.txt

实际执行时的问题

问题 3.1:requirements.txt 里 torch/torchaudio 版本老旧

requirements.txt 指定 torch==2.3.1,但我们的 CUDA 是 12.6 需要 torch>=2.5

解决:不单独装 PyTorch,直接复用已有环境(reset3)的 PyTorch 2.9.0 + CUDA 12.6。只装缺失的包:

bash 复制代码
pip install -r requirements.txt
# 已安装的 torch/torchaudio 会自动跳过

问题 3.2:matcha-tts 装不上

matcha-tts 0.0.7.2 依赖旧版 numpy/build 工具,与新版 setuptools 冲突。

解决

bash 复制代码
pip install matcha-tts --no-build-isolation --no-deps

问题 3.3:torchcodec 缺少 FFmpeg shared DLLs

新版 torchaudio(2.9.0)强制使用 torchcodec 来读写音频文件,但 torchcodec 需要 FFmpeg 的 .dll 动态库(shared 版本),而我们装的是 FFmpeg full_build(静态编译,没有 DLL)。

尝试 :装 conda 版 ffmpeg(有 DLL)→ 依然缺文件

最终解决:monkey-patch torchaudio.load,用 soundfile 替代:

python 复制代码
import torchaudio, soundfile as sf, torch

def _patched_load(path, **kwargs):
    audio, sr = sf.read(path)
    audio_t = torch.from_numpy(audio).float()
    if audio_t.ndim == 1:
        audio_t = audio_t.unsqueeze(0)
    else:
        audio_t = audio_t.T
    return audio_t, sr

torchaudio.load = _patched_load

问题 3.4:inference_webui.py 的 bert_path 用相对路径

python 复制代码
bert_path = "GPT_SoVITS/pretrained_models/chinese-roberta-wwm-ext-large"

新版 transformers 把这个路径当 HuggingFace repo ID 校验,拒绝加载。

解决:改为绝对路径:

python 复制代码
bert_path = os.path.join(os.path.dirname(__file__), "pretrained_models/chinese-roberta-wwm-ext-large")

坑 4:中文模型下载

GPT-SoVITS 依赖多个模型文件,下载方式各异:

模型 大小 下载方式
Chinese-RoBERTa-wwm-ext-large ~1.2GB from transformers import AutoModel
Chinese-HuBERT-base 180MB 直接从 HuggingFace 下载 pytorch_model.bin
fasttext 语言检测 ~400MB urllib.request.urlretrieve(url, ...)
GPT-SoVITS v2Pro 全套 ~5GB git lfs clone(实测最快)

GPT-SoVITS 主模型下载(推荐方式)

bash 复制代码
# git LFS 比 Python SDK 快得多
cd D:\zero_track\Reset
git clone --depth=1 https://huggingface.co/lj1995/GPT-SoVITS
# 如果 hf-mirror 不工作,加代理:
set HTTP_PROXY=http://localhost:9910

模型文件位置

复制代码
GPT-SoVITS/GPT_SoVITS/pretrained_models/
├── s1bert25hz-2kh-longer-epoch=68e-step=50232.ckpt  ← GPT 模型
├── v2Pro/s2Gv2Pro.pth                                ← SoVITS 模型
├── v2Pro/s2Gv2ProPlus.pth                            ← SoVITS ProPlus 模型
├── sv/pretrained_eres2netv2w24s4ep4.ckpt             ← 说话人编码器
├── chinese-roberta-wwm-ext-large/                     ← 文本编码器
├── chinese-hubert-base/                               ← 语音编码器
└── fast_langdetect/lid.176.bin                        ← 语言检测

坑 5:GPT-SoVITS 零样本输出重复提示词尾

问题:每句话开头会出现参考文本末尾的词语。

:参考文本是"土豆削皮上锅蒸熟酱油腌制,大火炒熟西兰花切成块,焯水 ",

目标文字"土豆削皮" → 输出"焯水土豆削皮"

根因:GPT-SoVITS 的零样本推理机制是把参考文本当"前缀"输入给语言模型,目标文字是"续写"。所以它"续写"时会先重复参考文本末尾的词,再开始说目标文字。

尝试的解决

复制代码
方法 1: 固定裁剪开头 0.4-0.5s 音频
  → 短句"土豆削皮"被裁掉一半,只听到"削皮"
  → ❌

方法 2: 提高静音阈值(5%)
  → 效果有限,因为跳过去的不是静音是语音
  → ❌

方法 3: 用 Whisper 逐字对齐裁剪
  → Whisper tiny 识别中文不准,"土豆削皮"识别成"塗斗消皮"
  → 匹配不上,反而把正确内容裁掉
  → ❌

方法 4: 改为逐句使用独立参考片段(最终方案)
  → 把完整参考音频按字幕切分成 5 段
  → 每句话用自己的那段音频 + 自己的文字做参考
  → 第 1 句:参考音频只有"土豆削皮",没有"焯水"
  → 模型没有"焯水"可重复 ✅

教训:零样本 TTS 的"内容重叠"问题,不是在输出端裁剪能解决的,要从输入端消除重叠。

批量切分工具prepare_voice.py --mode segment


坑 6:ffmpeg filter_complex 语法

问题:filter 字符串报错 "No option name near 'disable'"。

根因 :ffmpeg 用逗号(,)来分隔 filter chain 中的各个滤镜。表达式 max(1160/iw, 2112/ih) 里的逗号被 ffmpeg 错误解析为滤镜分隔符。

python 复制代码
# ❌ 错误写法
f"scale=iw*max({W}/iw,{H}/ih):ih*max({W}/iw,{H}/ih)"
# ffmpeg 理解为: scale=iw*max(1160/iw  →  然后 2112/ih) 成了下一个滤镜

# ✅ 正确写法
f"scale='iw*max({W}/iw,{H}/ih)':'ih*max({W}/iw,{H}/ih)'"
# 用单引号保护表达式,ffmpeg 会把引号内的逗号当作运算符而非分隔符

坑 7:emoji 导致 subprocess 崩溃

问题subprocess.run(capture_output=True, text=True) 捕获了包含 emoji 的输出,在 Windows GBK 编码下报 UnicodeDecodeError

解决:设环境变量让子进程用 UTF-8 输出:

python 复制代码
env["PYTHONIOENCODING"] = "utf-8"
result = subprocess.run(cmd, capture_output=True, text=True, env=env)

坑 8:音量和 BGM 平衡

问题:背景音乐要么听不到,要么太大盖过人声。

根因amix(inputs=2) 混合两路音频时,默认把各路的音量除以输入路数(即各减半)。

最终参数

python 复制代码
TTS: volume=8.0   # 原始 TTS 只有 RMS=0.035,提 8 倍到 RMS=0.28
BGM: volume=1.0   # Demucs BGM 有 RMS=0.0375
# 经 amix(÷2) 后:TTS≈0.14, BGM≈0.019, 混合≈0.08
# 原视频 RMS=0.133,已接近

Demucs BGM 的制作方式

bash 复制代码
# Demucs 把原视频分成 4 轨:人声、鼓声、贝斯、其他
# 把鼓声+贝斯+其他 3 轨混合 → 背景音乐(无 vocals)
D:\application\ffmpeg\bin\ffmpeg.exe -i bass.wav -i drums.wav -i other.wav \
  -filter_complex "[0:a][1:a][2:a]amix=inputs=3:duration=longest[bgm]" \
  -map "[bgm]" background_demucs.wav

最终部署清单

硬件要求

  • GPU: NVIDIA 4060 Ti (16GB VRAM) 或同等
  • 硬盘: 约 10GB(模型文件 + 依赖)
  • 内存: 16GB+
  • 系统: Windows 10/11

所需软件

软件 版本 安装方式
Python 3.10+ conda
PyTorch 2.9.0+cu126 pip
CUDA 12.6 NVIDIA 驱动自带
FFmpeg Gyan 版(full_build) 手动下载,需含 NVENC
Git LFS 最新 git lfs install

最终目录结构

复制代码
D:\zero_track\Reset\
├── video_maker\                      ← 主项目
│   ├── make_fast.py                  ← 主渲染脚本
│   ├── local_tts.py                  ← GPT-SoVITS 封装
│   ├── prepare_voice.py              ← 参考音频准备工具
│   ├── compare.py                    ← 视频对比分析
│   ├── server.py                     ← 手机端服务(FastAPI)
│   ├── templates/index.html          ← 手机端网页界面
│   ├── input/
│   │   ├── images/                   ← 放图片
│   │   ├── subtitles.txt             ← 字幕
│   │   └── music/
│   │       └── background_demucs.wav ← 背景音乐
│   ├── output/                       ← 生成视频
│   └── voices/                       ← 声音库
│
├── GPT-SoVITS\                       ← 声音克隆引擎
│   └── GPT_SoVITS/pretrained_models/ ← 预训练模型
│
└── output/                           ← 参考音频 / 分离结果
    ├── cloned_voice.wav              ← 原视频提取的人声
    └── ref_segments/                 ← 切分后的参考片段

一句话使用

bash 复制代码
set HTTP_PROXY=http://localhost:9910
cd D:\zero_track\Reset\video_maker
python make_fast.py --local-tts

项目总结

目标完成度

目标 完成度 说明
图片→竖屏视频 1160×2112,自动缩放填充
字幕叠加 半透黑底白字,底部居中
AI 配音 GPT-SoVITS 声音克隆
声音克隆 从原视频 15s 录音克隆
背景音乐 Demucs 分离
画面按配音切换 每张图显示时长=配音时长
GPU 加速 NVENC 硬件编码
手机服务端 video_maker_app/
清晰无杂音 ⚠️ 偶尔有极短的"诶"声
零样本完美效果 GPT-SoVITS 零样本对短句会有填充音

最终评价

能用的程度 :日常用 make_fast.py --local-tts 生成短视频完全可行。音色、节奏、BGM 都说得过去。

不能解决的:GPT-SoVITS 零样本对 3-5 字短句有时会带填充音,这是模型本身的局限,后处理无法完美消除。如果每句话写 8-15 字,效果会好很多。

遗留问题

网页端视频无法直接播放

问题server.py 生成的视频可以在浏览器下载,但无法在 <video> 标签中直接预览播放(播放器组件空白)。

尝试:修改视频像素格式(yuvj444p → yuv420p)、添加 faststart moov 前置、改用 StaticFiles 挂载、改用 FileResponse → 视频格式正确但浏览器依然不播。

可能原因:FastAPI 对 MP4 视频的 range request 支持不完整,或 h264_nvenc 编码的视频与浏览器解码器存在兼容问题。需要有多模态能力的模型协助调试浏览器端行为。

当前方案 :用户通过下载按钮拿到视频后在本地播放器播放,或直接使用 make_fast.py 命令行生成。

相关推荐
装不满的克莱因瓶1 小时前
掌握神经网络的模型结构
人工智能·python·深度学习·神经网络·机器学习·ai
深度学习lover1 小时前
<数据集>yolo安全手套佩戴识别<目标检测>
人工智能·yolo·目标检测·数据集·安全手套佩戴识别
抓蛙师1 小时前
【无标题】
人工智能
码云骑士1 小时前
AI 自动化测试
人工智能
愚公搬代码1 小时前
【愚公系列】《移动端AI应用开发》013-DeepSeek API开发与集成(深度集成与中间件架构)
人工智能·中间件·架构
段一凡-华北理工大学1 小时前
工业领域的Hadoop架构学习~系列文章17:Hadoop性能调优- 调度集群每一分性能
大数据·人工智能·hadoop·分布式·学习·架构·高炉炼铁
feiwuw1 小时前
Hermes Agent介绍
人工智能·hermes
故渊at1 小时前
第一板块:Android 系统基石与运行原理 | 第五篇:Context 上下文与资源配置体系
android·人工智能·opencv·context·上下文·资源配置体系
ice8130331811 小时前
【Python】调用opencv识别图片人脸位置
人工智能·python·opencv