前言
上一篇讲了"按目标大小压缩"的码率反推(链接),但压缩只是视频瘦身的一半。另一半是裁剪------很多视频里其实塞了大量"无用画面":
- 会议 / 课程录屏,顶部是菜单栏、底部是任务栏,甚至两侧有黑色信箱边;
- 从 B 站 / YouTube 下载的视频,上下自带大黑边(pillarbox / letterbox);
- 想把一个 16:9 的横屏 改成 9:16 的竖屏发抖音 / 视频号,直接上传会被自动压缩得很难看。
把无用画面裁掉,有两个直接好处:一是观感干净,二是像素总量下降,后续压缩的体积和耗时同步减少(裁剪和压缩是乘性关系,先裁 20% 面积 ≈ 后续压缩少编码 20% 的数据)。
本文聚焦 crop 和 scale 两个滤镜的工程用法,附可直接跑的命令和脚本,最后给出不想装环境时的在线替代。
环境准备
bash
# 验证 ffmpeg 在位
ffmpeg -version # 需 4.0+,cropdetect 早已支持
ffprobe -version
本文所有命令在 ffmpeg 6.0 / Windows 11 下验证。Windows 下
-f null -的/dev/null换成NUL。
一、crop 滤镜语法
crop=w:h:x:y
w、h:输出宽高x、y:裁剪区域左上角在原图里的坐标- 省略
x:y时默认居中裁剪 :crop=w:h - 宽度高度建议用表达式自动取偶数(编码器要求尺寸为偶数):
crop=iw:ih-100表示"高度减 100,宽度不变,居中"crop=ih*9/16:ih表示"按 9:16 竖屏裁切,高度用满"
二、实战 1:裁掉录屏的多余界面
一个 1920×1080 的屏幕录屏,顶部 40px 是浏览器标签栏、底部 50px 是任务栏,真正有用的画面在 y=40 到 y=1030。
bash
# 裁掉顶部 40px + 底部 50px,保留 1920×990
ffmpeg -i screen.mp4 -vf "crop=1920:990:0:40" -c:a copy screen_crop.mp4
-c:a copy 音轨不动只重封装,省时间。若想顺带压缩视频:
bash
ffmpeg -i screen.mp4 -vf "crop=1920:990:0:40" \
-c:v libx264 -crf 24 -c:a aac screen_crop_comp.mp4
三、实战 2:自动检测黑边(cropdetect)
不知道黑边具体多宽?用 cropdetect 让 ffmpeg 自己扫一遍,输出建议的裁剪参数:
bash
ffmpeg -i video.mp4 -vf cropdetect -f null NUL
输出类似:
[Parsed_cropdetect_0 @ ...] x1:0 y1:138 x2:1919 y2:941 w:1920 h:804 crop=1920:804:0:138
最后一行 crop=1920:804:0:138 就是建议值,直接套用:
bash
ffmpeg -i video.mp4 -vf "crop=1920:804:0:138" -c:a copy video_nobar.mp4
注意:cropdetect 是按抽样帧判断的,若视频前后黑边不一致(比如片头有、正片无),建议手动指定或分段处理。
四、实战 3:16:9 转 9:16 竖屏(中心裁剪)
短视频平台要竖屏。直接把 1920×1080 拉伸会变形,正确做法是裁出中间的竖条:
bash
# 高度用满 1080,宽度 = 1080 * 9/16 = 607.5 → 取偶数 608
ffmpeg -i landscape.mp4 -vf "crop=608:1080" -c:a copy portrait.mp4
用表达式更稳(不写死数字):
bash
ffmpeg -i landscape.mp4 -vf "crop=ih*9/16:ih" -c:a copy portrait.mp4
如果同时想缩小体积,叠加 scale:
bash
# 竖屏 + 缩到宽 540(高度自动 960),H.264 压缩
ffmpeg -i landscape.mp4 -vf "crop=ih*9/16:ih,scale=540:-2" \
-c:v libx264 -crf 26 -c:a aac portrait_small.mp4
scale=540:-2 的 -2 表示高度按宽度比例自动算,且取最近偶数(编码器硬性要求)。
五、用 Python 批量裁剪(带自动黑边检测)
把"检测 + 裁剪"封装一下,处理一堆录屏:
python
#!/usr/bin/env python3
"""auto_crop.py --- 自动检测黑边并裁剪一批视频
用法:
python auto_crop.py input_dir
"""
import os
import re
import subprocess
import sys
from pathlib import Path
def detect_crop(path: str) -> str | None:
"""用 cropdetect 拿建议的 crop 参数,返回 'w:h:x:y' 或 None"""
cmd = ["ffmpeg", "-i", path, "-vf", "cropdetect", "-f", "null",
"NUL" if os.name == "nt" else "/dev/null"]
out = subprocess.run(cmd, capture_output=True, text=True)
# cropdetect 的最后一条建议通常最准(基于全片抽样)
matches = re.findall(r"crop=(\d+:\d+:\d+:\d+)", out.stderr)
return matches[-1] if matches else None
def crop(path: str, crop_arg: str, dst: str):
subprocess.run(
["ffmpeg", "-y", "-i", path, "-vf", f"crop={crop_arg}",
"-c:a", "copy", dst],
check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
def main():
src_dir = Path(sys.argv[1] if len(sys.argv) > 1 else ".")
for f in src_dir.glob("*.mp4"):
arg = detect_crop(str(f))
if not arg:
print(f"[skip] {f.name} 未检测到黑边")
continue
dst = f.with_name(f"{f.stem}_crop.mp4")
print(f"[crop {arg}] {f.name} -> {dst.name}")
crop(str(f), arg, str(dst))
if __name__ == "__main__":
main()
实测一个文件夹里 5 段带黑边的录屏(均为 1920×1080,实际内容 1920×804),自动裁剪后:
| 文件 | 原始大小 | 裁剪后 | 体积变化 |
|---|---|---|---|
| rec01.mp4 | 312 MB | 261 MB | −16.3% |
| rec02.mp4 | 288 MB | 241 MB | −16.3% |
| rec03.mp4 | 401 MB | 336 MB | −16.2% |
| rec04.mp4 | 155 MB | 130 MB | −16.1% |
| rec05.mp4 | 220 MB | 184 MB | −16.3% |
裁剪掉约 25% 的无效画面高度(1080→804),因为音轨未重编码,总体积下降约 16%,符合预期(画面数据占比约 65--70%,裁掉 25% 高度 ≈ 画面数据减 25%,加权到整体约 16%)。
六、什么时候不该自己写命令
上面这套适合有 ffmpeg 环境、要批量处理的情况。如果是:
- 偶尔裁一个文件,装环境 + 算 crop 坐标的时间比裁剪本身长;
- 在非技术同事的机器上(客户现场、临时借用的电脑);
- 想要"上传即裁 + 压缩一步到位"。
浏览器方案更实际。我处理临时需求时会用 VideoCompress 这类在线工具,它的"画面裁剪"和"压缩"在同一个入口,拖动选框就能定裁剪区域、填目标大小就能压,不用记 crop=w:h:x:y 语法。它支持 40 多种格式输入、导出不带水印,单文件上限免费 1 GB(付费 10 GB)。
边界和所有云端方案一样:文件要上传到服务器(其说明为完成后 24 小时内自动删除),涉密、未公开素材不建议往任何在线服务传。
七、几个工程上的坑
1. crop 坐标越界会报错。 x + w 不能超过原宽、y + h 不能超过原高,否则 ffmpeg 直接失败。手动填坐标时务必先 ffprobe 拿真实分辨率。
2. 尺寸必须是偶数。 H.264/H.265 的色度采样要求宽高为偶数,奇数会报错或绿边。表达式里用 -2 或 trunc(.../2)*2 兜底最稳。
3. 裁剪和压缩顺序:先裁后压。 裁剪减少像素总量,后续编码的数据量随之下降,是先裁再压划算,不是反过来。
4. 竖屏中心裁会"丢两边内容"。 16:9 转 9:16 是从中间竖切,画面左右会被切掉。人物访谈、PPT 这类主体在中间的还好,主体偏左偏右的要手动定 x。
总结
视频瘦身 = 裁剪无用画面 + 压缩冗余数据,二者乘性叠加:
- 先用
cropdetect看有没有黑边/多余界面,有就crop=掉; - 需要换比例(横转竖)用
crop=ih*9/16:ih中心裁,注意左右内容取舍; - 叠加
scale=宽:-2控制输出尺寸,再用 libx264 压缩; - 批量交给脚本,一次性任务 / 临时环境用在线工具。
工具只是手段,先想清楚"这段视频最终在哪里看、什么比例",再决定怎么裁、怎么压。
标签:视频处理、FFmpeg、视频裁剪、音视频开发、短视频制作