@evio/ffai
v1.0.7
Published
一个基于 FFmpeg 的命令行工具,用于批量处理视频和音频文件,支持视频转码、音频合并、字幕添加等功能。
Downloads
785
Readme
FFmpeg 视频处理工具
一个基于 FFmpeg 的命令行工具,用于批量处理视频和音频文件,支持视频转码、音频合并、字幕添加等功能。适用于自动化视频制作、批量视频处理等场景。
✨ 功能特性
- 🎬 批量视频转码和拼接 - 支持多种视频格式转换为 MP4,自动拼接多个视频片段
- 🎵 多音频文件混音 - 将多个音频文件混合为一个音轨,支持 glob 模式批量处理
- 📝 自动添加字幕 - 支持自定义时间格式的字幕文件,自动渲染到视频上
- 🎲 智能视频选择 - 随机模式根据音频时长智能选择视频片段,避免重复
- 📦 Glob 模式匹配 - 灵活的文件匹配模式,支持通配符批量处理
- ⚙️ JSON 配置管理 - 基于配置文件的任务管理,支持批量任务处理
- 🔄 自动化工作流 - 一键完成从素材到成品的全流程处理
📋 前置要求
- Node.js >= 14.0.0
- FFmpeg - 必须在系统中安装并配置到环境变量
安装 FFmpeg
macOS:
brew install ffmpegUbuntu/Debian:
sudo apt update
sudo apt install ffmpegWindows: 从 FFmpeg 官网 下载并配置环境变量
🚀 快速开始
安装
# 克隆项目
git clone <repository-url>
cd <project-directory>
# 安装依赖
npm install
# 构建项目
npm run build
# 全局安装(可选)
npm link基本使用
# 执行任务配置文件
ffai build task.json📖 详细使用说明
任务配置文件
创建一个 JSON 配置文件来定义处理任务,支持多个任务批量执行:
[
{
"audios": ["audio1.mp3", "audio2.mp3"],
"videos": "videos/*.mp4",
"narration": "subtitle.txt",
"videoTranscodeable": true,
"videoPackMode": "random"
},
{
"audios": "bgm/*.mp3",
"videos": ["clip1.mp4", "clip2.mp4"],
"narration": "subtitle2.txt",
"videoPackMode": "all"
}
]配置参数详解
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| audios | string \| string[] | ✅ | 音频文件路径,支持数组或 glob 模式(如 bgm/*.mp3)⚠️ 重要:如果是数组,最终音频时长由第一个音频文件决定,其他音频会被混音叠加 |
| videos | string \| string[] | ✅ | 视频文件路径,支持数组或 glob 模式(如 videos/*.mp4) |
| narration | string | ✅ | 字幕文件路径,使用自定义时间格式 |
| videoTranscodeable | boolean | ❌ | 是否对视频进行转码,默认 false。启用后会将所有视频统一转码为 H.264/AAC 格式 |
| videoPackMode | 'random' \| 'all' | ❌ | 视频打包模式,默认 'all'- random: 根据音频时长随机选择视频片段- all: 使用所有视频文件 |
| fontFile | string | ❌ | 自定义字幕字体文件路径。如果不指定,macOS 默认使用宋体,其他系统需要提供字体路径 |
字幕文件格式
字幕文件使用简化的时间格式,每行一条字幕:
00:05-00:10 这是第一条字幕
00:12-00:18 这是第二条字幕
00:20-00:25 支持中文和英文
01:30-01:45 时间可以跨分钟格式说明:
- 时间格式:
MM:SS-MM:SS 字幕内容 - 开始时间和结束时间用
-分隔 - 时间和文本之间用空格分隔
- 支持跨分钟的时间范围
字幕样式:
- 字体大小:36px
- 字体颜色:白色
- 文字效果:黑色描边 + 阴影,确保在任何背景下清晰可见
- 位置:视频底部居中(距底部 300px)
- 字体:可通过
fontFile参数自定义,如果不指定则使用系统默认字体
跨平台字体路径参考:
- macOS:
/System/Library/Fonts/Supplemental/Songti.ttc(宋体) - Windows:
C:/Windows/Fonts/simhei.ttf(黑体)或C:/Windows/Fonts/msyh.ttc(微软雅黑) - Linux:
/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc(文泉驿正黑)
🔄 工作流程
工具会按以下步骤自动处理每个任务:
- 检查 FFmpeg - 验证 FFmpeg 是否可用
- 解析配置 - 读取任务配置文件,支持数组形式的多任务
- 解析素材文件 - 根据 glob 模式或数组匹配音频和视频文件
- 视频转码(可选)- 将视频统一转码为 MP4 格式(H.264 + AAC,44.1kHz,立体声)
- 获取时长信息 - 分析所有音频和视频的播放时长
- 音频混音 - 将多个音频文件混合为一个音轨(以第一个音频时长为准)
- 视频选择 - 根据
videoPackMode选择视频片段:random模式:随机选择视频直到总时长 ≥ 音频时长all模式:使用所有视频文件
- 视频拼接 - 将选中的视频片段拼接成完整视频
- 添加音频 - 为视频添加混音后的背景音频(使用
-shortest参数自动对齐) - 渲染字幕 - 将字幕渲染到视频上(白色文字 + 黑色描边阴影)
- 清理临时文件 - 删除中间过程文件,保留最终成品
- 输出成品 - 生成最终视频文件到
task-{index}/video.mp4
处理时间估算:
- 视频转码:取决于视频数量和时长,通常为实际播放时长的 0.5-2 倍
- 音频混音:通常在几秒内完成
- 视频拼接:较快,通常在 10 秒内
- 字幕渲染:取决于视频时长,通常为实际播放时长的 1-3 倍
📂 输出结构
每个任务会在当前目录下创建 task-{index} 文件夹:
task-0/
├── videos/ # 转码后的视频文件(如果启用 videoTranscodeable)
│ ├── 1.mp4
│ ├── 2.mp4
│ └── ...
├── tmp/ # 临时文件目录
├── audio.mp3 # 混音后的音频文件
└── video.mp4 # 最终输出的视频文件 ⭐💡 使用示例
示例 1:随机视频片段 + 多音频混音
[
{
"audios": ["bgm/music1.mp3", "bgm/music2.mp3"],
"videos": "clips/*.mp4",
"narration": "subtitles/narration.txt",
"videoTranscodeable": true,
"videoPackMode": "random"
}
]这个配置会:
- 混合两个背景音乐(以
music1.mp3的时长为准) - 从
clips/目录随机选择视频片段,直到总时长匹配音频 - 转码所有视频为统一格式(H.264/AAC)
- 添加字幕并输出到
task-0/video.mp4 - 使用系统默认字体
适用场景: 制作短视频、Vlog、产品宣传片等需要随机素材组合的场景
示例 2:使用所有视频 + 自定义字体
[
{
"audios": "audio/*.mp3",
"videos": ["intro.mp4", "content.mp4", "outro.mp4"],
"narration": "subtitle.txt",
"videoPackMode": "all",
"fontFile": "/path/to/your/font.ttf"
}
]这个配置会:
- 混合
audio/目录下的所有 MP3 文件 - 按顺序拼接三个视频文件(片头 + 内容 + 片尾)
- 不进行视频转码(使用原始格式,需确保格式一致)
- 使用自定义字体文件渲染字幕
- 添加字幕并输出到
task-0/video.mp4
适用场景: 固定结构的视频制作,如教程视频、演讲录制等
示例 3:批量处理多个任务
[
{
"audios": "task1/audio.mp3",
"videos": "task1/videos/*.mp4",
"narration": "task1/subtitle.txt",
"videoPackMode": "random"
},
{
"audios": "task2/audio.mp3",
"videos": "task2/videos/*.mp4",
"narration": "task2/subtitle.txt",
"videoPackMode": "all",
"fontFile": "C:/Windows/Fonts/msyh.ttc"
},
{
"audios": ["task3/bgm1.mp3", "task3/bgm2.mp3"],
"videos": "task3/clips/*.mp4",
"narration": "task3/subtitle.txt",
"videoTranscodeable": true,
"videoPackMode": "random"
}
]这个配置会:
- 依次处理三个独立任务
- 每个任务输出到对应的
task-0/、task-1/、task-2/目录 - 第二个任务使用 Windows 微软雅黑字体
- 支持不同的配置组合
适用场景: 批量生产系列视频、多语言版本视频等
示例 4:实际项目配置(参考 workspace/task.json)
[
{
"audios": ["workspace/007/007阿勒泰.mp3", "workspace/新疆背景音乐-已编辑.MP3"],
"videos": "workspace/007/*.mp4",
"narration": "workspace/007/007.txt",
"videoTranscodeable": true,
"videoPackMode": "random"
}
]这个配置会:
- 混合旁白音频和背景音乐(以旁白时长为准)
- 从
workspace/007/目录随机选择视频素材 - 转码所有视频确保格式统一
- 添加字幕文件
007.txt中的内容 - 输出到
task-0/video.mp4
适用场景: 旅游 Vlog、纪录片、风景视频等需要旁白 + 背景音乐的场景
示例 5:跨平台字体配置
[
{
"audios": "audio.mp3",
"videos": "videos/*.mp4",
"narration": "subtitle.txt",
"fontFile": "/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc"
}
]这个配置会:
- 在 Linux 系统上使用文泉驿正黑字体
- 确保中文字幕正确显示
跨平台字体路径:
- macOS:
/System/Library/Fonts/Supplemental/Songti.ttc - Windows:
C:/Windows/Fonts/simhei.ttf或C:/Windows/Fonts/msyh.ttc - Linux:
/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc(需先安装:sudo apt install fonts-wqy-zenhei)
🛠️ 开发
# 开发模式(使用 ts-node 直接运行)
npm run dev
# 构建项目
npm run build
# 构建并修复 ESM 导入路径
npm run fix📝 API 说明
项目提供了一系列可复用的函数,可以在其他项目中引入使用:
import {
getMediaDuration, // 获取媒体文件时长
transcodeVideo, // 转码单个视频
transcodeVideos, // 批量转码视频
concatVideos, // 拼接多个视频
mergeAudioFiles, // 混音多个音频文件
addBackgroundAudio, // 为视频添加背景音频
addSubTitles, // 为视频添加字幕
checkFfmpegAvailable // 检查 FFmpeg 是否可用
} from '@evio/ffai';函数详细说明
getMediaDuration(filePath: string): Promise<number>
获取媒体文件(音频或视频)的播放时长。
参数:
filePath: 媒体文件的完整路径
返回: Promise,resolve 时返回时长(秒)
示例:
const duration = await getMediaDuration('video.mp4');
console.log(`视频时长: ${duration} 秒`);transcodeVideo(input: string, output: string): Promise<void>
将单个视频转码为 MP4 格式(H.264 + AAC)。
参数:
input: 输入视频文件路径output: 输出视频文件路径
编码参数:
- 视频编码:H.264 (libx264)
- 音频编码:AAC
- 音频采样率:44.1kHz
- 音频声道:立体声
示例:
await transcodeVideo('input.avi', 'output.mp4');concatVideos(files: string[], outputFilePath: string, tmp?: string): Promise<void>
拼接多个视频文件为一个完整视频。
参数:
files: 视频文件路径数组outputFilePath: 输出文件路径tmp: 可选,临时文件目录(用于存放 videofiles.txt)
注意: 建议所有视频使用相同的编码格式、分辨率和帧率
示例:
await concatVideos(
['clip1.mp4', 'clip2.mp4', 'clip3.mp4'],
'final.mp4',
'./tmp'
);mergeAudioFiles(audioFiles: string[], outputFilePath: string): Promise<void>
混音多个音频文件,以第一个音频的时长为准。
参数:
audioFiles: 音频文件路径数组outputFilePath: 输出文件路径
混音规则:
- 使用 FFmpeg 的
amix滤镜 - 自动调整音量避免爆音
- 输出时长由第一个音频决定
示例:
await mergeAudioFiles(
['narration.mp3', 'bgm.mp3'],
'mixed.mp3'
);addBackgroundAudio(inputVideoPath: string, outputVideoPath: string, audioPath: string): Promise<void>
为视频添加背景音频。
参数:
inputVideoPath: 输入视频路径outputVideoPath: 输出视频路径audioPath: 音频文件路径
处理规则:
- 视频流直接复制,不重新编码
- 音频使用 AAC 编码
- 使用
-shortest参数,输出长度取视频和音频中较短的一个
示例:
await addBackgroundAudio(
'video.mp4',
'video_with_audio.mp4',
'bgm.mp3'
);addSubTitles(inputfile: string, outputfile: string, texts: string, fontfile?: string): Promise<void>
为视频添加字幕。
参数:
inputfile: 输入视频路径outputfile: 输出视频路径texts: 字幕文件路径(格式:MM:SS-MM:SS 文本内容)fontfile: 可选,字体文件路径
字幕样式:
- 字体大小:36px
- 颜色:白色
- 效果:黑色描边 + 阴影
- 位置:底部居中(距底部 300px)
示例:
await addSubTitles(
'video.mp4',
'video_with_subtitles.mp4',
'subtitle.txt',
'/path/to/font.ttf'
);checkFfmpegAvailable(): Promise<boolean>
检查系统中 FFmpeg 是否可用。
返回: Promise,resolve 时返回 true(可用)或 false(不可用)
示例:
const available = await checkFfmpegAvailable();
if (!available) {
console.error('FFmpeg 未安装或不可用');
}⚠️ 注意事项
- FFmpeg 必须安装 - 工具依赖 FFmpeg,请确保已正确安装并配置到环境变量
- 字幕字体配置 - 可通过
fontFile参数自定义字体路径,支持跨平台配置:- macOS:
/System/Library/Fonts/Supplemental/Songti.ttc - Windows:
C:/Windows/Fonts/simhei.ttf或C:/Windows/Fonts/msyh.ttc - Linux:
/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc
- macOS:
- 视频格式统一 - 强烈建议启用
videoTranscodeable以确保所有视频格式统一,避免拼接时出现黑屏、卡顿或音画不同步 - 文件路径规则 - 所有路径都相对于执行命令的当前目录(
process.cwd()) - 临时文件清理 - 处理完成后会自动清理中间过程文件(
video_concat.mp4、video_concat_audio.mp4、videofiles.txt),仅保留最终成品 - 音频时长规则 - 当
audios为数组时,最终音频时长由第一个音频文件决定,其他音频会被混音叠加 - 视频时长匹配 - 添加背景音频时使用
-shortest参数,输出视频长度会与音频或视频中较短的一个对齐 - 字幕文件编码 - 字幕文件必须使用 UTF-8 编码,避免中文乱码
- Glob 模式注意 - 使用 glob 模式时,文件匹配顺序可能不是字母顺序,建议使用数组明确指定顺序
- 磁盘空间 - 视频处理需要较大的临时存储空间,确保磁盘有足够空间(建议至少为源文件总大小的 2-3 倍)
🎯 最佳实践
项目结构建议
project/ ├── task.json # 任务配置文件 ├── audios/ # 音频素材目录 │ ├── narration.mp3 │ └── bgm.mp3 ├── videos/ # 视频素材目录 │ ├── clip1.mp4 │ └── clip2.mp4 ├── subtitles/ # 字幕文件目录 │ └── subtitle.txt └── task-0/ # 输出目录(自动生成) └── video.mp4视频素材准备
- 尽量使用相同分辨率和帧率的视频素材
- 如果素材格式不统一,务必启用
videoTranscodeable: true - 建议使用 1920x1080 (1080p) 或 1280x720 (720p) 分辨率
音频素材准备
- 旁白音频放在数组第一位,背景音乐放在后面
- 确保音频采样率一致(建议 44.1kHz)
- 背景音乐音量建议比旁白低 20-30%(可以预先处理)
字幕文件编写
- 使用文本编辑器保存为 UTF-8 编码
- 每条字幕时长建议 3-8 秒,便于阅读
- 字幕文本不要过长,建议每行不超过 20 个汉字
- 预留字幕间隔时间,避免连续出现
字体文件配置
- 在配置文件中使用
fontFile参数指定字体路径 - 确保字体文件存在且可读
- 使用支持中文的字体文件
- 不同操作系统使用对应的字体路径
- 在配置文件中使用
性能优化
- 如果不需要转码,关闭
videoTranscodeable可以大幅提升速度 - 批量任务建议分批处理,避免一次处理过多任务
- 使用 SSD 硬盘可以显著提升处理速度
- 如果不需要转码,关闭
质量控制
- 处理完成后检查输出视频的音画同步
- 验证字幕显示时间和内容是否正确
- 检查音频混音效果,确保旁白清晰可听
🐛 常见问题
Q: 提示 "FFmpeg is not available"
A: 请确保已安装 FFmpeg 并配置到系统环境变量中。可以运行 ffmpeg -version 验证安装。
Q: 视频拼接后出现黑屏或卡顿
A: 建议启用 videoTranscodeable: true 将所有视频转码为统一格式。不同编码格式的视频直接拼接可能导致兼容性问题。
Q: 字幕显示不正常或不显示
A:
- 检查字幕文件格式是否正确,时间格式必须为
MM:SS-MM:SS 文本内容 - 确保字幕文件使用 UTF-8 编码
- 检查时间范围是否在视频时长内
- 确保每行格式正确,时间和文本之间有空格
Q: 音频混音后声音太小或太大
A: FFmpeg 的 amix 滤镜会自动调整音量。如需手动控制,可以在 src/lib.ts 的 mergeAudioFiles 函数中修改 amix 参数,例如添加 weights 选项来调整各音频的权重。
Q: 字幕字体显示异常或乱码
A:
- 使用
fontFile参数指定正确的字体文件路径 - macOS 可以使用
/System/Library/Fonts/Supplemental/Songti.ttc(宋体) - Windows 可以使用
C:/Windows/Fonts/simhei.ttf(黑体)或C:/Windows/Fonts/msyh.ttc(微软雅黑) - Linux 需要安装中文字体,如
sudo apt install fonts-wqy-zenhei,然后使用/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc - 确保字体文件支持中文字符
Q: 任务配置文件必须是 .json 后缀吗?
A: 是的,工具会检查文件扩展名,必须使用 .json 后缀。
Q: 可以处理哪些视频格式?
A: FFmpeg 支持几乎所有常见视频格式(MP4、AVI、MOV、MKV、FLV 等)。建议启用 videoTranscodeable 转码为统一的 MP4 格式以确保兼容性。
Q: random 模式如何选择视频?
A: 工具会随机选择视频片段,累加时长直到 ≥ 音频时长。每个视频片段只会被选择一次,避免重复。如果所有视频总时长仍小于音频时长,则使用所有视频。
Q: 处理大文件时速度很慢怎么办?
A:
- 视频转码是最耗时的步骤,如果源视频已经是 MP4 格式,可以关闭
videoTranscodeable - 字幕渲染需要重新编码视频,可以在
src/lib.ts中调整-preset参数(如改为ultrafast)来加快速度,但会增大文件体积 - 考虑使用更强大的硬件或启用硬件加速
Q: 如何自定义字幕样式?
A: 在 src/lib.ts 的 addSubTitles 函数中修改 videoFilters 的 options,可以调整:
fontsize: 字体大小fontcolor: 文字颜色shadowcolor/shadowx/shadowy: 阴影效果borderw/bordercolor: 边框效果x/y: 字幕位置
Q: 输出视频的质量如何控制?
A: 在 src/lib.ts 中可以调整编码参数:
- 转码时的
-c:v libx264可以改为-c:v libx265(更高压缩率) - 字幕渲染时的
-crf 18控制质量(0-51,数值越小质量越高,18 为高质量) - 音频比特率
-b:a 192k可以调整为更高或更低的值
📄 License
ISC
🤝 贡献
欢迎提交 Issue 和 Pull Request!
贡献指南
- Fork 本项目
- 创建特性分支 (
git checkout -b feature/AmazingFeature) - 提交更改 (
git commit -m 'Add some AmazingFeature') - 推送到分支 (
git push origin feature/AmazingFeature) - 开启 Pull Request
开发建议
- 遵循现有代码风格
- 添加适当的注释和文档
- 测试新功能确保不影响现有功能
- 更新 README 文档(如有必要)
📚 相关资源
🔮 未来计划
- [ ] 支持更多字幕格式(SRT、ASS 等)
- [ ] 添加视频特效和转场效果
- [ ] 支持硬件加速编码(NVENC、QSV 等)
- [ ] 提供 GUI 界面
- [ ] 支持实时预览
- [ ] 添加进度条显示
- [ ] 支持视频裁剪和缩放
- [ ] 添加水印功能
- [ ] 支持多语言字幕
📞 联系方式
如有问题或建议,欢迎通过以下方式联系:
- 提交 Issue
- 发送邮件至:[[email protected]]
版本: 1.0.2
作者: @evio/ffai
最后更新: 2024
⭐ 如果这个项目对你有帮助,欢迎给个 Star!
