手机竖版视频编辑 是做什么的?
这里的大多数规则都来自一个在相应步骤上失败过的真实视频。references/research.md 中记录了原因和来源。references/resolve-ui.md 映射了 DaVinci Resolve 的控制界面,以便通过计算机操作来驱动。
部分情况尚未经过已发布的视频验证:HDR 源、30 fps 慢动作、镜头前的讲话、TikTok 和 Shorts 的安全框以及封面。这些命令仅在测试片段上运行过。references/other-cases.md 中记录了它们,并说明了每个命令的验证方式。当编辑依赖其中某项时,请告知用户。
流程:手机源文件、ffmpeg 剪切与稳定、色彩(DaVinci Resolve,或用于全帧操作的 scripts/grade.py)、Remotion 文字、ffmpeg 音频与母带。
剪切前
- 阅读客户的品牌规则(如有):禁用词汇、联系方式、AI 标注、以及发布前需要审批的内容。
- 检查每个源片段:
python -I scripts/probe_source.py clip.mp4。它会报告旋转、帧率及其是否可变、SDR 或 HDR、色彩标签和音频,然后列出该片段在剪切前需要处理的事项。典型手机片段为 SDR bt709,帧率约 30 或 60 fps。HDR、可变帧率和 30 fps 源分别需要额外步骤,请参考references/other-cases.md。背景谈话意味着原始声音保持静音。如果镜头中的人物正在对观众讲话,请查看同一文件中的“讲话”部分。 - 如果你使用另一个 AI 模型作为审核者,在决定前与其讨论想法,然后验证它所说的内容。
references/research.md列出了审核模型可能犯的错误类型。
节奏
- 每条视频一个想法。文字决定时长,而不是预设的目标长度。一个测试视频因客户在 10.5 秒或 13.5 秒内无法读完,所以需要 18.6 秒。
- 按每行出现的时间计算,每秒预留 10 个阿拉伯语字符。这故意放慢,因为观众同时还要在手机上观看画面。
- 每个镜头尽量有两个揭示点,并且它们之间至少有 1.5 秒的间隔。同时出现的文字行算作一个揭示点。
- 母语读者对节奏的判断比任何模型的判断都重要。
- 最强的视觉画面和钩子文字出现在第 0 帧,没有从黑色淡入。
- 避免突然的 3 倍速度变化。可以通过缓慢的渐变来处理糟糕的时刻。
60 fps 以 0.5 倍播放时,实际帧率为 30 fps,因此不需要插帧。30 fps 源没有多余帧,因此在放慢前请阅读 references/other-cases.md 中的慢动作部分。先稳定到 60 fps 的中间格式,然后再调整时间:
ffmpeg -ss S -t D -i raw.mp4 -vf "vidstabdetect=shakiness=6:accuracy=15:result=x.trf" -f null -
ffmpeg -ss S -t D -i raw.mp4 -vf "vidstabtransform=input=x.trf:smoothing=14:zoom=2:optzoom=0:interpol=bicubic,crop=W:H:X:Y,scale=1080:1920:flags=lanczos,fps=60" -an -c:v libx264 -preset veryfast -crf 10 -pix_fmt yuv420p im.mp4
python -I scripts/retime.py im.mp4 c1.mp4 --start 0.4 --frames 99 --keys 0:.5
从本技能的文件夹运行 scripts/ 路径。ffmpeg 需要 vidstab 滤镜。每个片段必须从零时间开始,因为非零开始时间会在 Resolve 中显示为黑帧。当使用 -ss 配合时间滤镜时,添加 setpts=PTS-STARTPTS,并用 ffprobe 检查 start_time。
如果手部进入静止镜头的最后几帧,可以通过保持前一帧来隐藏:trim=end_frame=N,setpts=PTS-STARTPTS,tpad=stop_mode=clone:stop_duration=0.6。
色彩
定义:这里的色彩指的是校正:中性的白色、自然的肤色、真实的产品颜色、镜头匹配。创意调色放在最后,且保持细微,产品颜色在调色后仍须测量准确。
根据镜头的需求选择路径:
- 仅全帧操作(色温、曝光、对比度、饱和度):使用
scripts/grade.py。它更快、可重复,且数值保留在可重新运行的命令中。 - 画面某部分需要单独修正(不同光线下的肤色、某个物体):使用 DaVinci Resolve 及其 Power Window。
两种路径都使用相同的测量、调整、测量循环以及以下目标值。
使用 grade.py
python -I scripts/grade.py still c1.mp4 1.5 before.png
python -I scripts/measure_grade.py before.png --patch counter:40,60,200,220 --skin 100,1450,1000,1920
python -I scripts/grade.py make c1.cube --frame before.png --neutral 40,60,200,220 --white 205 --contrast 1.06 --pivot 0.4 --lift -0.02
python -I scripts/grade.py still c1.mp4 1.5 check.png --lut c1.cube --compare
python -I scripts/grade.py apply c1.mp4 c1g.mp4 --lut c1.cube
--neutral 是一个应该呈灰色或白色的区域:台面、墙壁、纸张、白色盖子。make 会平衡其 R、G、B 通道,--white 设置最终亮度水平。选择照明均匀且未过曝的区域。在应用前,以全尺寸查看 --compare 帧,并测量已调色的一半。每个镜头一个 LUT,因为每个镜头有自己的色偏。
当增益将高光推过 250 时,添加 --knee 0.85。仅对明显噪点多、光线不足的片段使用 --denoise light,很少使用 --sharpen:手机已经进行了锐化,再增加会导致边缘和文字出现光晕。
在 Resolve 中创建的调色可以导出为 LUT:在 Color 页面右键点击片段的缩略图,选择“Generate LUT”,33 Point Cube。然后 grade.py apply --lut 可将其应用于任何片段。LUT 仅包含全帧操作,因此窗口操作不包含在内。
在 DaVinci Resolve 免费版中
将片段复制到一个 Resolve 可以访问的普通文件夹中(它无法打开某些应用数据文件夹,会显示“Path does not exist”)。将它们放在新时间线上,并打开 Parade 示波器。
按以下顺序操作,因为每个步骤都依赖于前一个:
- 平衡节点。 用 Gain 调整白色水平,用 Temp 调整色偏。正 Temp 使画面变暖。两个镜头中的同一条面必须匹配。
- 对比度节点。 调整 Contrast 和 Pivot,用 Lift 加深黑色,进行不超过 5 的小幅 Sat(饱和度)调整。
- 主体节点,仅在全局调整会损坏其他部分时使用。 使用柔和的 Power Window。在测试视频中,一个窗口修正了手部肤色,同时保持了产品颜色不变。
- 渲染、测量、调整、重复。两遍就足够了。
python -I scripts/measure_grade.py frame.png --patch counter:40,60,200,220 --skin 100,1450,1000,1920
目标值
- 中性表面:R、G、B 差值在约 3 到 5 以内。白色约 195 到 215,呈现明亮效果。
- 肤色色调接近 123 度。保持自然,因为矢量示波器上的线是参考,不是目标。
- 肤色亮度:指南建议根据肤色和场景,在 40% 到 70% 之间。使用此范围来发现错误,而非作为必须达到的数字。
- 高光部分中,约 2% 以下的像素达到 250+。
- 饱和度:比较调色前后的
chroma线。校正后 p95 应保持在接近原始值的位置。大幅跳跃意味着调色添加了场景中没有的颜色。 - 产品颜色在视频销售产品时必须保持真实。
- 同一表面的两个镜头测量结果相同。
各调整的作用:
- Tint 对红色手掌几乎无效。按通道调整 Gamma 修复了它:提高 G,稍微降低 R 和 B。
- Temp +300 对蓝色色偏过度调节,而 +130 是合适的。从小幅调整开始。
Remotion 中的阿拉伯语文字
assets/reelTemplate.tsx 是一个可用的模板。它将每个文本块保存为数据,并包含一个用于文本检查的 probe 合成。references/remotion-setup.md 涵盖了从零开始项目以及注册合成的方法。
规则:
- 使用粗体的阿拉伯语字体(模板使用 Alexandria 800),白色加上一种强调色,无边框,柔和的阴影。
- 在 1080x1920 的帧上,字号为 62 到 124 px。手机需要这么大的字号。
- 阿拉伯语的行高(line box)设为 1.5。在 1.22 时,字母的尾笔会碰到下一行。
- 所有字母位于 x 110-950 和 y 220-1475 范围内,以确保不被 Instagram 的右侧栏和底部栏遮挡。
- 使用
whiteSpace: nowrap,防止行意外换行。 - 钩子文字在第 0 帧显示。后续文字行大约间隔 1 秒,带有 6 帧的上升和淡出效果。
- 在文字后方添加柔和的深色条带,以保证文字下方的主体可见。
- 客户引述必须逐字保留,未经客户同意不得包含姓名或照片。
- 描述观众正在看到的内容。不要让标签暗示这是唯一的选项。
在文字更改后,渲染 probe 帧并进行检查:
npx remotion still ReelProbe out/p0.png --frame=0
python -I scripts/check_text.py out/p0.png out/p1.png out/p2.png out/p3.png
当两行文字的油墨距离小于 14 px 或字母离开安全框时,检查将失败。一个文字块最多容纳七行。
然后检查文字与真实画面的重叠效果。渲染每个镜头的最后一帧(此时所有文字行都在屏幕上),并按相同顺序传递这些帧:
npx remotion still Reel out/r0.png --frame=119
python -I scripts/check_text.py out/p0.png out/p1.png --real out/r0.png out/r1.png
每行都会获得一个对比度数值,该数值计算自文字周围画面最亮部分。数值低于 3.0 则失败。在测试视频中,强调色的文字得分在 3.2 到 4.6 之间,白色文字得分为 5 及以上。低分意味着需要在文字后方使用更强的深色条带,或移动文字块。
默认安全框是 Instagram 的。对于也发布到 TikTok 或 Shorts 的视频,添加 --platform all。这两个平台的安全框来自第三方指南,因此请在每个应用中预览上传效果。
然后,查看每个镜头结尾处的全尺寸帧。缩略图表格会隐藏碰撞,而文字后移动的物体只有在全尺寸下才能看到。在测试视频中,一把勺子穿过了一行文字。通过一个角起点的小幅缩放将其移开,同时也裁剪了多余的手指。
渲染与音频
npx remotion render Reel out/reel.mp4 --codec=h264 --crf=15 --muted --color-space=bt709
python -I scripts/beat_offset.py music.ogg --cuts 3.3,6.5,10.3 --length 13.5 --from 0 --to 40
--color-space=bt709 很重要。没有它,Remotion 会写入全范围的 bt470bg,且主色彩未知。
从最佳偏移点剪切音乐,淡出最后 1.2 秒,使用 -c:v copy 拼接,然后进行母带处理:
sh scripts/master.sh in.mov out.mp4 -14 0.4 0.75
最后一个数字是限制器天花板。AAC 音频编码会在其之上产生过冲,冲量取决于音轨本身,因此该脚本会测量它写入的文件并打印其响度和真实峰值。如果打印出 TOO HOT(真实峰值高于 -1 dBTP),请使用 0.7 重新运行。
手机扬声器会丢失大部分 300 Hz 以下的声音,因此要检查该频段:
ffmpeg -hide_banner -nostats -i out.mp4 -vn -af "highpass=f=300:poles=2,highpass=f=300:poles=2,lowpass=f=12000,ebur128" -f null - 2>&1 | tail -12
目标是在 -14 LUFS 的母带中,该频段达到 -20 LUFS 或更响亮。一个重低音轨测量为 -23.9 LUFS,在手机上听起来很沉闷。也要绘制波形图和频谱图,因为审核模型的时间戳并不总是与它们匹配。
AI 生成的音乐或人声需要平台的 AI 标签。生成的音乐要比视频稍长,因为被剪短的音轨无法干净地延长。
完成前的检查
- ffprobe 显示
yuv420p, tv, bt709, bt709, bt709,以及正确的时长和帧数。 check_text.py打印出 PASS,并包含--real帧。master.sh打印出的真实峰值等于或低于 -1 dBTP。- 如果视频显示在个人资料网格上,则需要存在封面帧(
references/other-cases.md)。 - 亲自查看全尺寸帧,包括第一帧和最后一帧以及每个剪切点之前的帧。
- 如果审核模型观看最终的 mp4,请向其提供已经做出的决定,以免它重新开启这些决定。
- 说明哪些内容未被检查。AI 无法听到音频或在手机上看到文件。
- 在替换已上传的文件后,重新上传,从公共链接验证,并更新任何指向旧文件的计划内容。
发布需要客户的批准。