添加片头片尾 是做什么的?
片尾片段是短小的MP4文件,带有自己的音效,每种方向有一个片段对,在偏好设置中列出。本技能将所有内容标准化为同一种格式,将片头、视频和片尾以短交叉淡入淡出(视频和音频)的方式连接起来,并渲染输出结果。
偏好设置
remote-video-editing/preferences.json(查找顺序同clean-voice-sidon):
| 键名 | 含义 |
|---|---|
stings | {"intro_16x9": url, "outro_16x9": url, "intro_9x16": url, "outro_9x16": url};URL或本地路径 |
sting_fade_s | 交叉淡入淡出长度,默认0.5 |
render_notes | 在哪里运行长编码任务(例如服务器而不是笔记本电脑)。请遵从这些说明。 |
如果未设置stings,请询问文件。该插件不附带任何品牌资产。
方向
读取显示的方向,而不是编码尺寸:手机将竖屏视频存储为1920x1080并带有旋转标记。使用以下命令检查:
ffprobe -v error -select_streams v:0 -show_entries stream=width,height:stream_side_data=rotation -of compact IN。
旋转90或-90会交换宽度和高度。ffmpeg在解码时会自动应用旋转。
- 竖屏(9:16)视频:使用
intro_9x16/outro_9x16,画布1080x1920。 - 横屏:使用16:9片段对,画布1920x1080。
- 竖屏视频的16:9裁剪(用于YouTube主信息流):画布1920x1080,视频缩放至1080高度居中显示,覆盖在其自身的模糊、变暗、放大的副本之上;使用16:9片段。下面的
[v1]链变为:
先对8秒裁剪片段([1:v]fps=30,split[a][b]; [a]scale=1920:1080:force_original_aspect_ratio=increase,crop=1920:1080,scale=480:270,boxblur=20:2,scale=1920:1080,eq=brightness=-0.06:saturation=0.9[bg]; [b]scale=-2:1080[fg];[bg][fg]overlay=(W-w)/2:0,setsar=1,format=yuv420p[v1]-ss 60 -t 8)进行测试,并在渲染完整视频之前显示一帧。
渲染
W:H是画布,F是淡入淡出长度(0.5),DI是片头时长,DV是视频时长(ffprobe format=duration)。
偏移量:第一次淡入淡出在DI-F处;第二次在DI+DV-2*F处。
ffmpeg -y -i intro.mp4 -i main.mp4 -i outro.mp4 -filter_complex "
[0:v]fps=30,scale=W:H,setsar=1,format=yuv420p[v0];
[1:v]fps=30,scale=W:H:force_original_aspect_ratio=decrease,pad=W:H:(ow-iw)/2:(oh-ih)/2,setsar=1,format=yuv420p[v1];
[2:v]fps=30,scale=W:H,setsar=1,format=yuv420p[v2];
[0:a]aresample=48000,aformat=channel_layouts=stereo[a0];
[1:a]aresample=48000,aformat=channel_layouts=stereo[a1];
[2:a]aresample=48000,aformat=channel_layouts=stereo[a2];
[v0][v1]xfade=transition=fade:duration=F:offset=DI-F[v01];
[v01][v2]xfade=transition=fade:duration=F:offset=DI+DV-2*F[v];
[a0][a1]acrossfade=d=F[a01];[a01][a2]acrossfade=d=F[a]" \
-map "[v]" -map "[a]" -c:v libx264 -preset medium -crf 20 -maxrate 10M -bufsize 20M -c:a aac -b:a 192k -movflags +faststart out.mp4
- 多个源片段:先拼接它们(相同的滤镜模式,或者如果它们共享编码器则使用concat分离器),然后将结果视为
main.mp4。 - 这是完整的重新编码:处理10分钟1080p视频需要几分钟的全核心运行。在Modal上运行,而不是在本地或家庭服务器上:将输入之后的参数(从
-filter_complex到+faststart)每行一个放在render.args中,然后运行$MODAL run "${CLAUDE_PLUGIN_ROOT}/scripts/ffmpeg_modal.py" --inputs intro.mp4,main.mp4,outro.mp4 --args-file render.args --out out.mp4(modal_command和run_notes来自偏好设置,用于指定Modal在哪里运行)。在同一个图中拼接多个片段(使用concat滤镜),而不是作为单独的通道。之后删除卷video-editing-work中该任务的文件夹。 - xfade要求两个输入具有相同的时间基准:在每个视频分支上放置
fps=30,settb=1/30(包括在concat之后),否则ffmpeg会报错“First input link main timebase (1/30) do not match”。 - 码率:保持上限(
-crf 20 -maxrate 10M -bufsize 20M)。对噪点较多的手机片段使用纯CRF 18会导致约24 Mbps,11分钟大约2 GB(2026-11-13)。YouTube无论如何都会重新编码,并建议1080p上传使用8-12 Mbps。 - 验证:输出时长约为
DI + DV + DO - 2*F,并检查DI-F/2(淡入淡出中间)、视频中间和结尾的帧。
手持镜头:在同一次渲染中稳定
手持拍摄的手机视频受益于轻度稳定(用户,2026-11-13,在第一次Hebrish周末更新发布时没有包含此项功能)。使用ffmpeg的vid.stab(libvidstab;Debian的ffmpeg——Modal镜像安装的版本——包含它;使用ffmpeg -filters | grep vidstab检查)。两个通道,都在Modal上运行:
- 检测(快速,仅分析,写入变换文件),针对每个源片段:
ffmpeg -i main.mp4 -vf vidstabdetect=shakiness=5:accuracy=15:result=main.trf -f null -作为独立的ffmpeg_modal.py任务运行(参数-vf/vidstabdetect=...:result=/work/<job>/main.trf/-f/null,输出-),或者向脚本中添加检测步骤。.trf文件必须与输入文件一起放在卷中。 - 变换在主渲染中,放在该片段视频分支的最开始,在尺寸调整和缩放之前:
vidstabtransform=input=main.trf:smoothing=20:zoom=2:optzoom=0,unsharp=5:5:0.4smoothing大约15-30(帧)可保持自然运动;固定的zoom=2(百分比)可隐藏移动的边界,而不会出现optzoom=1在说话人头部上引起的抽动效果。轻微的unsharp可抵消重采样引入的柔化。
先对8秒裁剪片段进行测试,并将一帧静态图像和一个短片段展示给用户,然后再进行完整渲染。如果libvidstab缺失,deshake是一个一次通道的替代方案(效果较弱)。此场景不需要AI稳定器。
制作片尾片段
使用的片尾片段是由品牌SVG文件通过一个小型Pillow脚本以及生成的音效渲染而成的。使用find-script(标签logo、sting、intro)查找该脚本,不要使用视频模型重新生成logo:视频模型会扭曲字体形状。