mcpField
V
video-edit

video-edit

github.com/melvynx创意与媒体6951 次安装1 周前更新
代码仓库

关于 video-edit

video-edit 是将原始录制转换为竖屏短视频或横屏 YouTube 视频的技能。它涵盖转录、剪辑选择、字幕、画面元素、质量检查、渲染及交付文件。

主要功能

  1. 01检查并准备源视频
  2. 02生成带词级时间的语音转录
  3. 03根据停顿和重录制作剪辑段
  4. 04添加字幕、开场卡片和标注
  5. 05渲染前检查静帧
  6. 06导出视频、字幕和发布文案

适用场景

  1. 01将单次录制剪成竖屏短视频
  2. 02制作横屏 YouTube 视频
  3. 03生成供其他编辑器使用的 SRT 字幕
  4. 04使用已保存的剪辑数据修改成片

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/melvynx/video-agent-skills --skill video-edit

安装后在 Claude Code 中输入/video-edit确认已加载。

附带文件references/remotion-short.mdreferences/style.md

详细介绍

视频剪辑

输入一段原始拍摄素材,输出一段完成的视频:video-agent/edits/<slug>/final.mp4。可以是竖屏短视频,也可以是用于 YouTube 的完整横屏视频。

这些工具免费,并在创作者的机器上运行:

  • Remotion(用 React 编写视频)及其官方 TikTok 模板,内置本地语音转文字功能和词级时间戳(whisper.cpp)。
  • ffmpeg,用于检查和处理音频。

固定且简洁的视觉风格:references/style.md。绘制该风格的代码位于 references/remotion-short.md。

如何运行

  • 运行前检查:node -v && ffmpeg -version && git --version。缺少任何一项:停止并引导他们前往 /video-setup tools。
  • 使用创作者的语言交流。每个较长步骤(安装、转录、渲染)开始前,先用一行说明你要做什么,以及预计耗时。
  • 阅读 video-agent/voice.md,了解语言和强调色。没有语音文件:询问这两项,或使用英语和 #FFD400。
  • 指定风格(请求中使用 style <name>,由 /video-steal 创建):阅读 video-agent/styles/<name>.md,并在 style.md 的基础上应用该风格。指定风格中的值优先;按说明将其音效、贴纸和调色应用到剪辑中;未指定的内容则沿用 style.md。
  • <slug>:使用小写字母和连字符,不要包含句点或空格(转录器会在文件名的第一个句点处截断)。
  • 步骤 1 和 2 在项目根目录运行。从步骤 3 开始,所有命令都在 video-agent/studio/ 中运行,路径均相对于该目录。

1. 拍摄素材和格式

使用他们指定的文件;若未指定,则使用 video-agent/takes/ 中最新的文件。检查它:

ffprobe -v error -show_entries format=duration:stream=codec_type,codec_name,width,height,r_frame_rate,avg_frame_rate,color_transfer -of compact "<take>"
  • 没有音频流:停止并告知他们。
  • color_transfer 为 smpte2084 或 arib-std-b67:这是 HDR 素材(iPhone 默认格式)。不要转换:Remotion 会在渲染时将其映射为普通颜色。提醒他们下次拍摄时在相机设置中关闭 HDR 视频。
  • 否则,如果是 .webm 或可变帧率(r_frame_rate 和 avg_frame_rate 不同):进行转换,因为 Remotion 和 ffmpeg 剪辑都会出现偏移。从现在起使用新文件作为拍摄素材:
    ffmpeg -y -i "<take>" -vf fps=30 -c:v libx264 -crf 18 -preset veryfast -pix_fmt yuv420p -c:a aac -b:a 192k -ar 48000 "video-agent/takes/<slug>-30fps.mp4"
    

然后确定格式。他们已说明格式(short、long、“for YouTube”、“a reel”):按他们说的做。否则,根据拍摄素材选择,并用一行说明选择结果:

格式构图适用情况默认设置
短视频Short,1080x1920素材时长不足 90 秒,或他们想制作短视频、reel、TikTok 视频开启字幕、添加开场卡片,每 8 到 10 秒添加一个提示标注
长视频Wide,1920x1080横屏素材时长超过 90 秒、完整 YouTube 视频、教程、vlog开启字幕(询问:YouTube 观众通常更喜欢单独提供 .srt,设置 showCaptions: false)、除非他们需要,否则不添加开场卡片;最多每 30 到 60 秒添加一个提示标注;添加章节
  • 横屏素材制作短视频:画面会裁切至中央。如果人物不在画面中央,提醒他们。
  • 竖屏素材制作长视频:画面会被裁切成很窄的一条。不要这样做;建议制作短视频。
  • 长视频:先说明耗时。使用 medium 模型时,笔记本电脑上的转录速度约为实时速度(20 分钟的素材约需 20 分钟;small 快 2 到 3 倍);渲染每秒视频需要 3 到 5 秒(15 分钟的剪辑约需 1 小时)。这两项任务都会在后台运行。

下文中的 <comp> 为 Short 或 Wide。

查找对应的脚本:在 video-agent/scripts/ 中找到匹配的脚本(slug 相同或首行相同)。没有脚本也没关系,剪辑将仅依据转录内容进行。

2. 工作室(仅首次)

先告知对方:需要下载约 1 GB 的软件包;首次转录时还需要下载语音引擎及其模型(0.5 至 1.5 GB),并进行几分钟的设置。

git clone --depth 1 https://github.com/remotion-dev/template-tiktok video-agent/studio
cd video-agent/studio
npm i
  • 删除 video-agent/studio/.git,使工作室成为项目中的普通文件夹。
  • 语言设置在 whisper-config.mjs 中:
    • 英语:保留 WHISPER_MODEL = "medium.en" 和 WHISPER_LANG = "en"。
    • 其他语言:设置 WHISPER_MODEL = "medium"(较慢的机器可用 "small",大小为 466 MB),并将 WHISPER_LANG 设为对应的代码("fr"、"es"、"de"、"pt"……)。
  • 添加 Short 和 Wide 合成以及字体包:按照 references/remotion-short.md 的第 1 至 3 节操作,然后运行 npx tsc --noEmit。如果工作室创建时还没有 Wide:将 src/Short/index.tsx 和 src/Root.tsx 替换为当前版本的第 2 和第 3 节内容。
  • 可选:从 Claude 获取更好的 Remotion 代码:npx skills add remotion-dev/skills。

3. 转录

cp "../takes/<take file>" public/<slug>.mp4
node sub.mjs public/<slug>.mp4

这会写入 public/<slug>.json:每个词对应一条记录,格式为 { "text": " word", "startMs", "endMs", "confidence" }。如果文件已有对应的 JSON,则会跳过;删除该 JSON 即可重新转录。

根据脚本修正听错的词(姓名、品牌、数字):只修改 text,绝不要改时间。

4. 剪辑列表

找出实际的静音,然后列出词与词之间的间隔:

ffmpeg -nostats -i public/<slug>.mp4 -af silencedetect=noise=-35dB:d=0.3 -f null - 2>&1 | grep silence_
node -e 'const w=require("./public/<slug>.json"),G=350,B=100,A=150,s=(ms)=>(ms/1000).toFixed(2);let r=[{fromMs:Math.max(0,w[0].startMs-B)}];for(let i=1;i<w.length;i++){const g=w[i].startMs-w[i-1].endMs;if(g>G){console.error(`gap ${s(w[i-1].endMs)} -> ${s(w[i].startMs)} (${g} ms) after "${w[i-1].text.trim()}"`);r[r.length-1].toMs=w[i-1].endMs+A;r.push({fromMs:w[i].startMs-B})}}r[r.length-1].toMs=w[w.length-1].endMs+300;console.log(JSON.stringify(r))'

第二条命令会打印所有超过 0.35 秒的间隔及其前一个词,随后列出带有 style.md 所述边距的保留 ranges。然后修正这些范围:

  1. silencedetect 未报告的间隔(呼吸声、轻声词语、音乐):将对应的两个范围合并。
  2. 重录:逐行检查脚本。如果某一行(或开头 3 个词)出现多次,保留最后一次完整录制,并删除从第一次录制的第一个词到保留版本起始处的范围。
  3. 删除口误(如重说前的“呃”或半个词)、钩子之前的所有内容,以及偏离脚本的谈话。

长视频:规则相同,但间隔阈值使用 0.5 秒而非 0.35 秒(G=500):完整视频需要留出一些停顿,思考时的停顿可以保留。保留有价值的补充内容;删掉没有意义的旁枝内容。没有脚本时,连续说两遍的句子算作重录:保留最后一次。

渲染前,用几行展示结果:

Take 1:42 → short 0:47 (-55 s)
- 38 pauses cut (41 s)
- 3 retakes dropped: line 2 (x2), line 7
- dropped "ok let me do that again" at 0:58

5. 动态效果

根据脚本的视觉备注(如果没有,则自行选择):

  • 钩子卡片:屏幕上的钩子,不超过 6 个词,其中一个词用 *accent* 标记,时长 2 至 3 秒。
  • 标注:人物说出的数字、结果或工具名称,大约每 8 至 10 秒出现一次,间隔至少 4 秒(长视频:最多每 30 至 60 秒一次,只标注关键数字)。atMs = JSON 中对应词的 startMs。

写入 public/<slug>.edit.json(格式见 remotion-short.md 第 4 节)。

6. 质量检查,然后渲染

渲染 3 或 4 张静帧:钩子(第 30 帧)、一个标注、视频中段的一条字幕、最后一秒(长视频:在整个视频中均匀选取 6 至 8 张静帧)。仅短视频:将平台的安全区域叠加到每张图上:

npx remotion still <comp> out/<slug>-qc-30.png --frame=30 --props=public/<slug>.edit.json
ffmpeg -y -v error -i out/<slug>-qc-30.png -vf "drawbox=x=0:y=0:w=iw:h=230:[email protected]:t=fill,drawbox=x=0:y=1440:w=iw:h=480:[email protected]:t=fill,drawbox=x=850:y=900:w=230:h=540:[email protected]:t=fill" out/<slug>-qc-30-safe.png

检查每张 -safe PNG(长视频:检查每张静帧):红色区域内不能有文字(应用的按钮、名称和描述会遮住文字);字幕应位于人脸下方;钩子卡片要清晰可读;标注不能遮住眼睛;强调色要正确。修正编辑文件,然后:

npx remotion render <comp> out/<slug>.mp4 --props=public/<slug>.edit.json

笔记本电脑上,每秒视频约需 3 至 5 秒渲染时间。在后台运行,并告知所需时间。

7. 音频

只有对方提出要求时才添加音乐(使用免版税音乐,例如 YouTube Audio Library),音量比人声低 22 dB:

ffmpeg -y -i out/<slug>.mp4 -stream_loop -1 -i "<music file>" -filter_complex "[1:a]volume=-22dB[m];[0:a][m]amix=inputs=2:duration=first:normalize=0[a]" -map 0:v -map "[a]" -c:v copy -c:a aac -b:a 192k out/<slug>-music.mp4

然后调整渲染结果的响度(有音乐时为 out/<slug>-music.mp4)。Remotion 不会调整人声响度,而对这么短的片段直接执行 loudnorm,结果会低 2 至 3 LU。先测量:

ffmpeg -nostats -i out/<slug>.mp4 -af ebur128=peak=true -f null - 2>&1 | grep -E "^\s+(I|Peak):"

增益 = -14 减去 I: 的数值(例如 I = -17.0 → 3.0dB),并添加限制器:

mkdir -p ../edits/<slug>
ffmpeg -y -i out/<slug>.mp4 -c:v copy -af "volume=<gain>dB,alimiter=limit=0.8:level=false" -c:a aac -b:a 192k -ar 48000 ../edits/<slug>/final.mp4

以相同方式测量 final.mp4:I 在 -15 到 -13 之间且 Peak 低于 -1 dBFS 即为合适。

8. 交付

在 video-agent/edits/<slug>/ 中:

  • final.mp4,可直接发布。
  • captions.srt:将台词调整到剪辑后的时间线上,每条字幕最多 7 个词,每句话结束后新增一条字幕。平台会将其作为隐藏字幕读取。
    node -e 'const e=require("./public/<slug>.edit.json"),w=require("./public/"+e.captions),F=30,fr=(ms)=>Math.round(ms/1000*F);let at=0;const p=e.ranges.map(r=>{const f=fr(r.fromMs),n=Math.max(1,fr(r.toMs)-f),q={...r,s:(at-f)/F*1000};at+=n;return q});const o=w.flatMap(x=>{const q=p.find(q=>x.startMs>=q.fromMs&&x.startMs<q.toMs);return q?[{t:x.text.trim(),a:x.startMs+q.s,b:Math.min(x.endMs,q.toMs)+q.s}]:[]});const ts=(ms)=>new Date(Math.max(0,Math.round(ms))).toISOString().slice(11,23).replace(".",",");let c=[],n=0,out="";const flush=()=>{if(c.length)out+=`${++n}\n${ts(c[0].a)} --> ${ts(c[c.length-1].b)}\n${c.map(x=>x.t).join(" ")}\n\n`;c=[]};for(const x of o){c.push(x);if(c.length===7||/[.?!]$/.test(x.t))flush()}flush();process.stdout.write(out)' > ../edits/<slug>/captions.srt
    
  • edit.json:public/<slug>.edit.json 的副本,以便日后重新制作视频。
  • post.md:发布时要粘贴的文案(见下文)。
  • 仅限长视频,在 post.md 中添加 章节,用于 YouTube 描述:每隔 1 到 3 分钟添加一个,主题变化时添加,时间点以剪辑后的时间线为准(参照 captions.srt),第一条从 0:00 开始,至少 3 条,每条时长不少于 10 秒。

然后说明视频时长、剪掉了什么、文件位置,并提出一项修改建议(“开场卡片再短一些?少几个提示?换个强调色?”)。修改方式:编辑 JSON,然后重新渲染(步骤 6 和 7)。下一步:/video-publish <slug>。

发布文案

post.md 根据脚本和 voice.md 编写,使用视频所用的语言:

  • 标题(YouTube Shorts):少于 60 个字符,主题要出现在前 3 个词中。长视频:少于 70 个字符,体现视频承诺的内容,且与视频相符。
  • 说明文字:前 125 个字符要能独立表达完整意思(应用会在此处截断,隐藏后续内容)。接着写 1 到 2 行简短文字,再提出一个请求,使用 voice.md 中的那个请求。
  • 搜索词:观众会用来搜索该视频的 2 或 3 个词,以普通文字写在标题或第一行中。
  • 话题标签:末尾添加 3 到 5 个与主题相关的标签。不要使用 #fyp 或 #viral。
  • 不写视频中没有提到的内容:不要添加新的数字、主张或承诺。

如果已安装 video-script 技能,请对文案运行其 humanize 流程(references/humanize.md)。

Title: Your hook is too long
Caption: Nobody hears word 12 of your hook. Cut it to 12 words and put the result first.
Try it on your next three videos.
Follow for one script fix a day.
#shortformvideo #videohooks #contentcreator

CapCut、Premiere 或不使用 Remotion

有些创作者更喜欢使用自己的编辑器;此外,对于超过 3 人的公司,Remotion 需要付费许可证。执行步骤 1 到 4,使用范围写入 public/<slug>.edit.json("hook": null、"callouts": []),跳过步骤 5 到 7,并提供 captions.srt(步骤 8)以及:

  • cuts.md:列出保留片段的范围,供手动剪辑:
    mkdir -p ../edits/<slug>
    node -e 'const e=require("./public/<slug>.edit.json"),t=(ms)=>new Date(ms).toISOString().slice(14,23);for(const r of e.ranges)console.log(t(r.fromMs)+" → "+t(r.toMs))' > ../edits/<slug>/cuts.md
    
  • 或者仅使用 ffmpeg 进行简单剪辑:
    SEL=$(node -e 'const e=require("./public/<slug>.edit.json");console.log(e.ranges.map(r=>`between(t,${r.fromMs/1000},${r.toMs/1000})`).join("+"))')
    ffmpeg -y -i public/<slug>.mp4 -vf "select='$SEL',setpts=N/FRAME_RATE/TB" -af "aselect='$SEL',asetpts=N/SR/TB" -c:v libx264 -crf 18 -c:a aac ../edits/<slug>/cut.mp4
    

诚实说明限制

  • whisper.cpp 可能会听错人名和术语:脚本会修正这些内容,但数字要人工核对。
  • 剪辑效果不错,但并不完美:可能会剪掉一口气,或最后一个轻声音节。发布前请完整观看一遍。
  • Claude 无法听取原始录音:它依赖时间点和 silencedetect。音频质量差(有音乐、回声或两个人声)会让两者的效果都变差。
  • 安全区域兼顾 TikTok、Reels 和 Shorts;各应用的按钮位置略有不同。
  • Remotion 许可证:个人、最多 3 人的公司和非营利组织可免费使用;规模更大的公司需要购买公司许可证(remotion.pro/license)。

评论

支持 Markdown