在日常视频处理场景中,我们经常需要将字幕(SRT)合并到视频中 ,尤其是从 YouTube、B 站等平台下载的视频,字幕通常是单独的 .srt 文件。
本文将介绍一种稳定、可复用、支持中文编码 的方案:
👉 使用 Python 调用 FFmpeg,将 MP4 视频与 SRT 字幕无损合并为一个新视频文件。
一、实现目标
- ✅ 合并 MP4 视频 + SRT 字幕
- ✅ 不重新编码视频 / 音频(速度快、无损)
- ✅ 正确处理 UTF-8 中文字幕
- ✅ 设置字幕语言元数据(如
chi) - ✅ 封装为可复用的 Python 函数
二、环境准备
1️⃣ 安装 FFmpeg
Ubuntu / Debian
bash
sudo apt install ffmpeg
macOS(Homebrew)
bash
brew install ffmpeg
Windows
- 下载:https://ffmpeg.org/download.html
- 解压后将
ffmpeg.exe加入系统PATH
验证是否安装成功:
bash
ffmpeg -version
2️⃣ Python 环境
- Python 3.7+
- 无需额外第三方库(只使用标准库)
三、核心思路说明
我们要做的事情本质上就是执行下面这条 FFmpeg 命令:
bash
ffmpeg -sub_charenc UTF-8 \
-i input.mp4 \
-i subtitle.srt \
-c:v copy \
-c:a copy \
-c:s mov_text \
-metadata:s:s:0 language=chi \
output.mp4
关键点解释:
| 参数 | 作用 |
|---|---|
-sub_charenc UTF-8 |
强制字幕编码为 UTF-8(防止中文乱码) |
-c:v copy |
视频流不重新编码 |
-c:a copy |
音频流不重新编码 |
-c:s mov_text |
MP4 容器支持的字幕编码 |
language=chi |
设置字幕语言为中文 |
四、完整 Python 实现代码
python
import subprocess
import os
import sys
def validate_file(file_path, file_type="file"):
"""
校验文件是否存在
:param file_path: 文件路径
:param file_type: 文件类型描述(用于错误提示)
"""
if not os.path.exists(file_path):
raise FileNotFoundError(f"{file_type} 不存在: {file_path}")
print(f"{file_type} 校验通过: {file_path}")
return True
def merge_video_with_subtitles(video_path, srt_path, output_path):
"""
使用 FFmpeg 将 MP4 视频与 SRT 字幕合并
不重新编码视频和音频,支持 UTF-8 中文字幕
"""
# 1. 校验输入文件是否存在
validate_file(video_path, "视频文件")
validate_file(srt_path, "字幕文件")
# 2. 构建 FFmpeg 命令
ffmpeg_cmd = [
"ffmpeg",
# 输入视频文件
"-i", video_path,
# 输入字幕文件
"-i", srt_path,
# 视频流直接拷贝,不重新编码
"-c:v", "copy",
# 音频流直接拷贝,不重新编码
"-c:a", "copy",
# 将 SRT 转换为 MP4 支持的 mov_text 字幕格式
"-c:s", "mov_text",
# 设置字幕语言元数据为中文
"-metadata:s:s:0", "language=chi",
# 输出文件
output_path
]
# 3. 强制指定字幕编码为 UTF-8,防止中文乱码
ffmpeg_cmd.insert(3, "-sub_charenc")
ffmpeg_cmd.insert(4, "UTF-8")
try:
# 4. 执行 FFmpeg 命令
result = subprocess.run(
ffmpeg_cmd,
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
print(f"字幕合并成功,输出文件: {output_path}")
except subprocess.CalledProcessError as e:
# FFmpeg 执行失败时输出错误信息
print("FFmpeg 执行失败:")
print(e.stderr)
raise
except Exception as e:
# 其他异常
print(f"执行过程中发生错误: {e}")
raise
def main():
"""
主函数,定义输入输出路径
"""
# 视频文件路径
video_path = r"SSYouTube.online_Gesture Drawing Practice _ 20 and 40 sec. poses_1080p.mp4"
# 字幕文件路径
srt_path = r"SSYouTube.online_Gesture Drawing Practice _ 20 and 40 sec. poses_1080p.srt"
# 输出视频路径
output_path = "output.mp4"
# 合并视频与字幕
merge_video_with_subtitles(video_path, srt_path, output_path)
if __name__ == "__main__":
try:
main()
except Exception as e:
print(f"程序异常退出: {e}")
sys.exit(1)
五、代码结构解析
1️⃣ 文件校验(防止低级错误)
python
validate_file(video_path, "video")
validate_file(srt_path, "subtitle")
- 避免 FFmpeg 报错才发现文件不存在
- 提前失败,错误更友好
2️⃣ 为什么使用 subprocess.run
优点:
- ✔ 可控参数列表(避免 shell 注入)
- ✔ 可捕获 stdout / stderr
- ✔ 出错自动抛异常(
check=True)
3️⃣ 为什么选择 mov_text
- MP4 容器 不支持直接嵌入 SRT
mov_text是 MP4 官方支持的字幕格式- 各大播放器(VLC、QuickTime、手机)兼容性好
六、常见问题与解决方案
❓ 中文字幕乱码?
✅ 一定要加:
bash
-sub_charenc UTF-8
并确保 .srt 本身是 UTF-8 编码。
❓ 想把字幕"烧录"到画面中?
那就不能用 -c:v copy,需要使用:
bash
-vf subtitles=xxx.srt
👉 这是 硬字幕,不可关闭,且会重新编码(速度慢)。