Video Converter
用途
提供确定性的视频/音频格式转换能力:容器互转、重编码、压缩、缩放、裁剪、音频提取、GIF 互转、批量处理与拼接。所有操作通过 scripts/vc.py(PyAV 实现)完成。
关键前提:本机未安装系统 ffmpeg,也不需要安装。 PyAV 自带 FFmpeg 8.x 库(libavcodec 62 / libavformat 62),编码器覆盖 libx264、libx265、VP9、SVT-AV1、ProRes、MPEG-4、GIF、AAC、MP3、Opus、FLAC、ALAC、PCM,并支持 Apple VideoToolbox 硬件加速。不要建议用户 brew install ffmpeg——本机没有 Homebrew,也不需要它。
环境
必须使用已装好 PyAV 的托管解释器:
PY=~/.workbuddy/binaries/python/envs/default/bin/python
VC=~/.workbuddy/skills/video-converter/scripts/vc.py
$PY $VC doctor # 转换前先跑一次,确认编码器可用
若 doctor 报 PyAV 缺失,装进托管 venv(PyPI 可达,不需要 GitHub):
~/.workbuddy/binaries/python/envs/default/bin/pip install av
不要用系统 python3(缺 PyAV),也不要 pip install -g。
命令速查
$PY $VC probe <file> [--json] # 探测:容器/编码/分辨率/帧率/时长/音轨
$PY $VC convert <in> <out> [选项] # 单文件转换(输出扩展名决定目标容器)
$PY $VC batch <文件或目录...> --to <ext> [选项] # 批量;--recursive 递归;-o 指定输出目录
$PY $VC extract-audio <in> [out] [--format mp3] # 抽音轨(无输出名则按源名推断)
$PY $VC to-gif <in> [out] [--width 480 --fps 12] # 视频转 GIF
$PY $VC gif-to-video <in> [out] # GIF 转视频
$PY $VC concat <a> <b> ... -o <out> # 拼接(要求编码/分辨率/采样率一致)
$PY $VC presets # 列出预设与支持的容器
$PY $VC doctor # 运行时自检
通用选项(convert / batch):
| 选项 | 说明 |
|---|---|
--preset <名> |
质量预设,见下表 |
--crf N |
质量 0-51,越小越好(x264/x265/VP9/AV1) |
--vbitrate 2M / --abitrate 128k |
指定码率(覆盖 crf) |
--scale 1280:-2 |
精确缩放(宽 1280,高按比例取偶) |
--max-width 1280 |
只缩小不放大(预设内部用这个) |
--fps 30 |
输出帧率转换(走 fps 滤镜,帧数与时长精确) |
--start 5 --duration 10 |
裁剪:自第 5 秒起取 10 秒 |
--vcodec / --acodec |
直接指定编码器 |
--no-audio / --no-video |
丢弃音轨 / 只保留音频 |
--copy-streams |
只换容器不重编码(最快,秒级) |
--hwaccel |
VideoToolbox 硬件编码(最快,同码率质量略逊 libx264) |
--keep-subs |
保留字幕(需配合 --copy-streams) |
--overwrite |
覆盖已存在的输出 |
--json / --verbose / --quiet |
结构化结果 / 打印解析后的参数 / 静默 |
预设
| 预设 | 适用场景 |
|---|---|
web |
通用网页播放,≤1080p,H.264+AAC,fps≤30 |
web-1080p / web-720p / web-480p |
固定分辨率上界,只缩不放 |
mobile |
手机友好,小体积 |
hq |
高质量 H.264(crf 18) |
archive |
近无损归档(crf 14 + FLAC,配 mkv/mov) |
hevc |
H.265,同画质更小,兼容性稍差 |
av1 |
压缩率最高,需较新播放器 |
hw |
VideoToolbox 硬件编码,最快 |
gif |
动图(无音轨) |
audio |
仅音频 |
copy |
仅换容器,不重编码 |
显式选项永远覆盖预设值。未指定 --preset 时,编码器由目标容器决定(mp4→libx264+aac,webm→vp9+opus,avi→mpeg4+mp3,flv→libx264+aac,……)。
支持的容器
- 视频:
mp4m4vmovmkvwebmaviflvtsm2tsmpg3gpgif - 音频:
mp3m4aaacwavflacoggogaopusaiffcaf
目标容器由输出扩展名决定。编码器与容器不兼容时会被自动替换并打印 note(例如往 .webm 里指定 libx264 会被换成 libvpx-vp9)。
关键规则(易踩坑)
- GIF 没有音轨。视频转 GIF 必然丢音频,这是格式限制而非缺陷,交付时主动说明。
- webm 只接受 VP8/VP9/AV1 + Opus/Vorbis。转 H.264 进 webm 会被自动换成 VP9。
- libopus 只支持 8000/12000/16000/24000/48000 Hz。44.1kHz 源会自动重采样到 48kHz,并打印 note。
- 字幕只有
--copy-streams --keep-subs能保留;重编码路径一律丢弃字幕(会打印 note)。 concat要求所有输入的编码/分辨率/采样率完全一致,不一致直接报错并给出修复建议(先统一转码再拼)。它不做自动重编码。--max-width不放大,--scale按字面执行。需要放大请用--scale并加--allow-upscale。--copy-streams只在容器兼容时可用。编码器不兼容时不要用它,会产生坏文件。- 输出已存在时拒绝执行,除非
--overwrite;批量模式下已存在的文件自动跳过。
转换后必须校验
vc.py 每次转换都会自行复检产出文件(大小、容器、时长、流数量),并在时长偏差超过 6% 时打印 WARNING。不要忽略 WARNING——它通常意味着参数不兼容或裁剪时间窗为空。
需要人工复核时:
$PY $VC probe <输出文件>
核对该文件的时长是否与源/裁剪目标相符、音轨是否存在、分辨率与帧率是否符合要求。
典型场景
# 压缩一个过大的手机视频,保持 720p
$PY $VC convert big.mov out.mp4 --preset web-720p
# 仅换容器,不损失画质(秒级完成)
$PY $VC convert input.mkv output.mp4 --copy-streams --overwrite
# 整个目录批量转 mp4,输出到单独目录
$PY $VC batch ~/Movies/raw --to mp4 --preset web-1080p -o ~/Movies/web --recursive
# 抽取音轨为 mp3
$PY $VC extract-audio talk.mp4 talk.mp3 --abitrate 192k
# 截取 5 秒制作为 GIF 动图
$PY $VC to-gif demo.mp4 demo.gif --start 12 --duration 5 --width 640 --fps 15
# 拼接多段录制(先确认编码一致)
$PY $VC concat part1.mp4 part2.mp4 part3.mp4 -o full.mp4
详细编码器矩阵、参数取舍与故障排查见 references/format-matrix.md。