视频编辑器 是做什么的?
概述
AI 辅助视频工作流程,由三个引擎驱动:
- ffmpeg -- 编辑现有素材(修剪、压缩、合并、调整大小、速度、稳定、水印、音频、GIF、缩略图、转场、字幕)
- Remotion -- 创建新的视频内容(标题卡、下三分之一、结束卡、预告片、动画叠加层)
- Whisper -- 转录和字幕生成
附加功能:
- 硬件加速:通过
h264_videotoolbox / hevc_videotoolbox 在 Apple Silicon 上实现
- 主题集成:与来自
~/design-assets/color-palettes/ 的设计资产集成
- 平台预设:适用于 YouTube、Instagram、TikTok、Twitter 等
- 工作区缓存:用于 Remotion,避免重复执行
npm install
何时使用
对 ANY 这些用户意图触发:
| 类别 | 关键词 |
|---|
| 基本编辑 | 修剪、剪切、剪辑、缩短、分割 |
| 压缩 | 压缩、减小大小、缩小、变小、优化 |
| 合并 | 合并、组合、连接、拼接、缝合 |
| 调整大小 | 调整大小、缩放、裁剪、填充、宽高比、竖屏、横屏、方形 |
| 速度 | 加速、减速、慢动作、延时摄影、快进、倒放 |
| 稳定 | 稳定、抖动、平滑、修复抖动 |
| 转场 | 淡入淡出、交叉淡入淡出、溶解、擦除、转场 |
| 字幕 | 字幕、SRT、转录、语音转文字 |
| 标题卡 | 标题卡、片头、开场、动画文字 |
| 下三分之一 | 下三分之一、姓名标签、字幕条、姓名条 |
| 结束卡 | 结束卡、片尾、结束画面、结尾 |
| 预告片 | 预告片、预告、宣传片、精彩集锦、蒙太奇 |
| 缩略图 | 缩略图、海报、帧提取、截图 |
| GIF | GIF、动画图像、循环、表情包 |
| 水印 | 水印、Logo 叠加、品牌 |
| 音频 | 音频、音量、标准化、响度、静音、淡入、淡出、混音、提取音频 |
| 信息 | 信息、详情、时长、分辨率、编码器、码率、元数据 |
| 流水线 | 流水线、批量、工作流、多步骤 |
| 平台 | YouTube、Instagram、TikTok、Twitter、Reels、Shorts |
命令参考
编辑命令 (ffmpeg)
| 命令 | 描述 | 示例 |
|---|
/trim | 从视频中裁剪一段 | "修剪 video.mp4 从 0:30 到 1:45" |
/compress | 通过质量控制减小文件大小 | "压缩到 10MB 以下" |
/merge | 将多个片段合并为一个 | "合并 clip1.mp4 和 clip2.mp4,带淡入淡出" |
/resize | 更改尺寸、宽高比、裁剪或填充 | "调整大小为 1080x1080 方形" |
/speed | 加速、减速或倒放 | "2 倍速" 或 "0.5 倍慢动作" |
/stabilize | 消除相机抖动 (vidstab 双通道) | "稳定 shaky.mp4" |
/watermark | 在视频上叠加图片或文字 | "添加 logo.png 到右下角" |
/audio | 音量、标准化、混音、淡入淡出、提取、静音 | "将音频标准化到 -14 LUFS" |
/thumbnail | 提取帧作为图片 | "在 0:15 处截取缩略图" |
/gif | 从视频片段创建动画 GIF | "从 0:05 到 0:10 创建 GIF,宽度 320px" |
/extract | 提取音频或字幕轨道 | "提取音频为 mp3" |
/info | 显示视频元数据和流信息 | "信息 video.mp4" |
创建命令 (Remotion)
| 命令 | 描述 | 示例 |
|---|
/title-card | 支持主题的动画标题卡 | "标题卡:Coming Soon,wad 主题,缩放动画" |
/lower-third | 动画名称/标题叠加 | "下三分之一:John Doe,CEO,现代风格" |
/end-card | 带 CTA 和社交媒体的动画片尾 | "结束卡:订阅!,@handle,ea 主题" |
/teaser | 带转场和标题的多片段蒙太奇 | "从 clips/ 文件夹创建预告片,30 秒" |
转录命令 (Whisper)
| 命令 | 描述 | 示例 |
|---|
/transcribe | 从语音生成 SRT/VTT | "转录 interview.mp4" |
/add-captions | 转录并将字幕烧录到视频上 | "添加字幕到 talk.mp4" |
编排
| 命令 | 描述 | 示例 |
|---|
/pipeline | 多步骤处理链 | "修剪,添加标题卡,为 Instagram 压缩" |
工作流
步骤 1:检查可用工具
which ffmpeg ffprobe && echo "ffmpeg: ok"
node --version && echo "node: ok"
which whisper && echo "whisper: ok" || echo "whisper: not installed (captions need manual .srt)"
ffmpeg -encoders 2>/dev/null | grep videotoolbox && echo "hw accel: ok" || echo "hw accel: not available"
ffmpeg -filters 2>/dev/null | grep vidstab && echo "vidstab: ok" || echo "vidstab: not available (brew install ffmpeg with --with-libvidstab)"
如果缺少 ffmpeg:"用 brew install ffmpeg 安装"
如果缺少 Node.js:"从 https://nodejs.org 安装或运行 brew install node"
如果缺少 vidstab:"用 vidstab 重新安装 ffmpeg:brew install ffmpeg --with-libvidstab"
步骤 2:分类请求
| 用户意图 | 引擎 | 路径 |
|---|
| 编辑现有素材 | ffmpeg | 步骤 3a |
| 创建新视频内容 | Remotion | 步骤 3b |
| 音频操作 | ffmpeg 音频滤镜 | 步骤 3a |
| 信息/检查 | ffprobe | 步骤 3a |
| 组合流水线 | 编排两者 | 步骤 3c |
| 平台发布 | 调整大小 + 压缩预设 | 步骤 3a |
| 转录 | Whisper + ffmpeg | 步骤 3a |
步骤 3a:ffmpeg 路径
- 如果没有提供,询问输入文件
- 用 ffprobe 检查:
ffprobe -v quiet -print_format json -show_format -show_streams "<file>"
- 硬件加速检测 (macOS Apple Silicon):
ffmpeg -encoders 2>/dev/null | grep h264_videotoolbox
- 输出冲突处理:
OUTPUT="trimmed_video.mp4"
COUNTER=2
while [ -f "$OUTPUT" ]; do
OUTPUT="trimmed_video_${COUNTER}.mp4"
COUNTER=$((COUNTER + 1))
done
- 构建 ffmpeg 命令
- 用通俗语言解释每个标志
- 说明输出文件名(绝不覆盖源文件)
- 询问:“我要运行这个吗?”
- 执行,然后验证:
if [ $? -eq 0 ]; then
echo "成功"
ffprobe -v quiet -print_format json -show_format "$OUTPUT" | grep -E '"duration"|"size"'
else
echo "错误——请检查上面的 ffmpeg 输出"
fi
- 报告输出路径 + 文件大小 + 时长
输出命名约定:
| 命令 | 输出模式 |
|---|
| 修剪 | trimmed_<filename> |
| 压缩 | compressed_<filename> |
| 合并 | merged_output.<ext> |
| 调整大小 | resized_<filename> |
| 速度 | speed_<factor>x_<filename> |
| 稳定 | stabilized_<filename> |
| 水印 | watermarked_<filename> |
| 字幕 | captioned_<filename> |
| 音频提取 | <name>.mp3 |
| 音频修改 | audio_<filename> |
| 字幕提取 | <name>.srt |
| 缩略图 | thumb_<name>_<timecode>.jpg |
| GIF | <name>.gif |
步骤 3b:Remotion 路径
- 检查 Node.js 是否已安装
- 工作区缓存——重用现有工作区:
WORKSPACE="/tmp/remotion-workspace"
if [ -d "$WORKSPACE/node_modules" ]; then
echo "重用缓存的 Remotion 工作区"
else
echo "创建 Remotion 工作区(首次运行)..."
mkdir -p "$WORKSPACE"
cp -r ~/project-templates/remotion-video/* "$WORKSPACE/"
cd "$WORKSPACE" && npm install
fi
- 主题加载:从
~/design-assets/color-palettes/ 加载:
- 根据需要编写或更新 composition 源文件
- 可用的 compositions:
TitleCard——带多种动画预设的动画标题
LowerThird——带强调条的姓名/标题叠加
EndCard——带 CTA、社交媒体、Logo 的片尾
Teaser——带 TransitionSeries 的多片段蒙太奇
- 渲染:
cd "$WORKSPACE"
npx remotion render src/index.ts <CompositionId> /path/to/output.mp4 \
--props='{"text":"Title","bg":"#09090B","fg":"#FFFFFF","accent":"#7C3AED"}'
- 将输出复制到用户的工作目录
- 报告输出路径 + 时长
步骤 3c:组合流水线
对于多步骤请求(例如,“制作一个带标题卡、片段和结束卡的预告片”):
- 规划——在执行前向用户描述每个步骤
- 创建——首先生成任何 Remotion 内容(标题卡、结束卡)
- 处理——用 ffmpeg 修剪/调整源片段大小
- 组装——用转场将所有部分合并,使用 ffmpeg
- 完成——如果指定了目标平台,则进行压缩
- 在主要阶段之间确认(创建 vs 编辑 vs 组装)
ffmpeg 快速参考
修剪(无损)
ffmpeg -ss <start> -to <end> -i input.mp4 -c copy trimmed_input.mp4
压缩——网络(CRF 23)
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k compressed_input.mp4
压缩——硬件加速(macOS)
ffmpeg -i input.mp4 -c:v h264_videotoolbox -b:v 5M -c:a aac -b:a 128k compressed_input.mp4
带淡入淡出转场的合并
ffmpeg -i clip1.mp4 -i clip2.mp4 \
-filter_complex "[0][1]xfade=transition=fade:duration=1:offset=<offset>,format=yuv420p[v];[0:a][1:a]acrossfade=d=1[a]" \
-map "[v]" -map "[a]" merged_output.mp4
调整大小 / 缩放
ffmpeg -i input.mp4 -vf "scale=1920:1080" resized_input.mp4
ffmpeg -i input.mp4 -vf "scale=1080:-1" resized_input.mp4
ffmpeg -i input.mp4 -vf "crop=min(iw\,ih):min(iw\,ih)" cropped_input.mp4
ffmpeg -i input.mp4 -vf "scale=1080:1080:force_original_aspect_ratio=decrease,pad=1080:1080:(ow-iw)/2:(oh-ih)/2:black" padded_input.mp4
速度更改
ffmpeg -i input.mp4 -vf "setpts=0.5*PTS" -af "atempo=2.0" speed_2x_input.mp4
ffmpeg -i input.mp4 -vf "setpts=2.0*PTS" -af "atempo=0.5" speed_0.5x_input.mp4
ffmpeg -i input.mp4 -vf "setpts=0.25*PTS" -af "atempo=2.0,atempo=2.0" speed_4x_input.mp4
ffmpeg -i input.mp4 -vf "reverse" -af "areverse" reversed_input.mp4
水印叠加
ffmpeg -i input.mp4 -i logo.png \
-filter_complex "overlay=W-w-20:H-h-20" watermarked_input.mp4
ffmpeg -i input.mp4 -i logo.png \
-filter_complex "overlay=20:20" watermarked_input.mp4
ffmpeg -i input.mp4 -i logo.png \
-filter_complex "[1]format=rgba,colorchannelmixer=aa=0.3[wm];[0][wm]overlay=(W-w)/2:(H-h)/2" watermarked_input.mp4
ffmpeg -i input.mp4 \
-vf "drawtext=text='My Brand':fontsize=24:[email protected]:x=W-tw-20:y=H-th-20" watermarked_input.mp4
视频稳定(vidstab 双通道)
ffmpeg -i shaky.mp4 -vf vidstabdetect=shakiness=10:accuracy=15 -f null -
ffmpeg -i shaky.mp4 -vf vidstabtransform=smoothing=30:input=transforms.trf stabilized_shaky.mp4
音频操作
ffmpeg -i input.mp4 -af "volume=1.5" audio_input.mp4
ffmpeg -i input.mp4 -af "loudnorm=I=-14:TP=-1:LRA=11" audio_input.mp4
ffmpeg -i video.mp4 -i music.mp3 \
-filter_complex "[0:a]volume=1.0[a1];[1:a]volume=0.3[a2];[a1][a2]amix=inputs=2:duration=first[a]" \
-map 0:v -map "[a]" audio_input.mp4
ffmpeg -i input.mp4 -af "afade=t=in:ss=0:d=3,afade=t=out:st=<end-3>:d=3" audio_input.mp4
ffmpeg -i input.mp4 -an muted_input.mp4
ffmpeg -i input.mp4 -i newtrack.mp3 -c:v copy -map 0:v:0 -map 1:a:0 replaced_audio_input.mp4
GIF 创建(双通道调色板以保证质量)
ffmpeg -ss <start> -t <duration> -i input.mp4 \
-vf "fps=15,scale=320:-1:flags=lanczos,palettegen" palette.png
ffmpeg -ss <start> -t <duration> -i input.mp4 -i palette.png \
-filter_complex "[0:v]fps=15,scale=320:-1:flags=lanczos[v];[v][1:v]paletteuse" output.gif
rm palette.png
缩略图提取
ffmpeg -ss <timestamp> -i input.mp4 -frames:v 1 -q:v 2 thumb_input_<timestamp>.jpg
ffmpeg -i input.mp4 -vf "fps=1/<interval>,scale=320:-1,tile=4x4" thumb_grid_input.jpg
烧录 .srt 字幕
ffmpeg -i input.mp4 -vf "subtitles=captions.srt:force_style='FontSize=24,PrimaryColour=&H00FFFFFF'" captioned_input.mp4
提取音频
ffmpeg -i input.mp4 -vn -c:a libmp3lame -q:a 2 output.mp3
视频信息
ffprobe -v quiet -print_format json -show_format -show_streams input.mp4
Remotion 快速参考
缓存工作区设置
WORKSPACE="/tmp/remotion-workspace"
if [ ! -d "$WORKSPACE/node_modules" ]; then
cp -r ~/project-templates/remotion-video/* "$WORKSPACE/"
cd "$WORKSPACE" && npm install
fi
TitleCard Composition
import { AbsoluteFill, spring, useCurrentFrame, useVideoConfig, Img } from 'remotion';
type Animation = 'fade' | 'slide-up' | 'slide-down' | 'zoom' | 'typewriter' | 'glitch' | 'blur-in';
export const TitleCard: React.FC<{
text: string;
subtitle?: string;
bg?: string;
fg?: string;
accent?: string;
animation?: Animation;
logo?: string;
}> = ({ text, subtitle, bg = '#09090B', fg = '#FFFFFF', accent = '#7C3AED', animation = 'fade', logo }) => {
const frame = useCurrent
…
[为翻译而截断]