Use FFmpeg to compress video files into low-bitrate MP4, reducing file size while preserving clear audio. Automatically detects hardware and selects the optimal encoding scheme (Apple Silicon uses VideoToolbox hardware acceleration by default).
Use cases
- Video files are too large, and only the audio information needs to be kept, with the video picture serving as auxiliary reference
- Batch compress multiple video files in a directory
- Lower the video bitrate to save storage space
- Remove silent and static segments in the middle of a video (such as breaks, black screens, silent gaps), while keeping the cut segments for review
Function modes
This skill supports two working modes:
Mode 1: Compression (default)
Compress videos into low-bitrate MP4 to reduce file size.
Mode 2: Silent/static segment cutting
Detect and remove segments in the video thatsimultaneously satisfythe following conditions:
- Audio silence(no sound)
- Static picture(consecutive frames have almost no change, such as no operation during a break, black screen)
Suitable for: invalid content such as breaks during course recording, silent waiting when no one is in a meeting room, etc.
Default workflow (compression mode)
1. Confirm input
Confirm the file path or directory path provided by the user. The following video formats are supported:
.mp4 .mov .avi .mkv .webm .flv .wmv .ts
2. Confirm parameters
Default configuration (no adjustment needed in most scenarios):
| Parameter | Default value | Description |
|---|---|---|
| CRF quality value | 23 | Adaptive quality, the smaller the value the higher the quality (software encoding only) |
| Maximum bitrate | 2500k | VBV bitrate upper limit |
| Audio bitrate | 96k | AAC speech audio quality |
| Encoding preset | veryfast | Balance between speed and compression ratio (software encoding only) |
| Encoder | Auto-detect | Apple Silicon defaults to HEVC VT, others to x264 |
| Concurrent threads | Automatic | VideoToolbox defaults to 1 (shared hardware encoder, multiple concurrent tasks are actually slower), software encoding defaults to ≤8 |
| Output suffix | _compressed |
Output filename suffix |
For detailed configuration instructions, see references/config.md。
3. Execute compression
# 单个文件
python3 scripts/compress.py -i <文件路径>
# 多个文件(并发压缩)
python3 scripts/compress.py -i <文件1> <文件2> <文件3>
# 整个目录
python3 scripts/compress.py -i <目录路径>
# 混合:文件 + 目录
python3 scripts/compress.py -i <文件1> <目录路径> <文件2>
Specify custom parameters:
python3 scripts/compress.py -i <文件1> <文件2> --crf 28 -a 64k --preset medium -j 2
4. Output report
After compression is complete, output the result for each file:
文件名 原始大小 压缩后大小 压缩比
video1.mp4 120.5 MB 28.3 MB 76.5%
─────────────────────────────────────────────────
合计 205.7 MB 47.4 MB 77.0%
Silent/static segment cutting workflow
When to use
Use this mode when the user mentions the following scenarios:
- There is a break in the middle of the video that needs to be cut out
- The video has long static/silent segments
- Remove gaps, silence, and black screens from recordings
1. Execute cutting
python3 scripts/trim_silences.py -i <视频文件路径>
Use default parameters (detect both silence and static at the same time; only segments of at least 3 seconds count).
Specify custom parameters:
# 仅检测静音片段(不考虑画面是否静止)
python3 scripts/trim_silences.py -i <路径> --mode silence
# 仅检测画面静止片段(不考虑是否有声音)
python3 scripts/trim_silences.py -i <路径> --mode static
# 自定义阈值:更严格的静默检测
python3 scripts/trim_silences.py -i <路径> --noise-db -40 --min-duration 5
Mode Selection Recommendations
| Video Type | Recommended Mode | Description |
|---|---|---|
| During course recording breaks | both |
Satisfies both silence + static simultaneously, no erroneous cuts |
| Meeting idle periods | both or static |
If there is air conditioner white noise throughout, use both |
| Competition/movie commentary (sound throughout) | static |
Only cuts static parts of the picture |
| Surveillance footage (fixed picture) | static |
Almost no audio needed |
2. Understanding the Output
After cutting is complete, the output:
| File | Description |
|---|---|
原文件名_trimmed.mp4 |
Fine-cut version (target segments removed) |
原文件名_cuts/ |
Directory where cut segments are stored |
原文件名_cuts/_report.json |
Timestamp report of cut segments |
In the cut segments directory, each segment is saved as a separate MP4 file, with the filename containing the start and end times for easy review.
3. Parameter Description
| Parameter | Default Value | Description |
|---|---|---|
--noise-db |
-30 | Silence detection decibel threshold, smaller is stricter |
--scene-threshold |
0.05 | Static picture threshold 0~1, smaller is stricter (slight page changes acceptable) |
--min-duration |
120 | Minimum segment duration (seconds), default 2 minutes, only cuts long segments |
--mode |
both | Detection mode: both=silence+static simultaneously, silence=silence only, static=static picture only |
--crf |
23 | CRF quality value |
--maxrate |
2500k | Maximum bitrate limit |
--bufsize |
2500k | VBV buffer size |
--audio-bitrate |
96k | Output audio bitrate |
--preset |
veryfast | Encoding preset |
--codec |
Auto-detect | Encoder selection (hevc_vt / h264_vt / x264 / x265 / x264_fast) |
Hardware Acceleration
This tool automatically detects system hardware and selects the optimal encoding scheme:
| Platform | Encoder | Speedup (measured) | Output Format | Description |
|---|---|---|---|---|
| Apple Silicon (M1/M2/M3/M4) | hevc_videotoolbox | 2-5x(1080p60) / 5-15x(720p30) | HEVC/H.265 | Automatically uses hardware encoding |
| Apple Silicon (fallback) | h264_videotoolbox | 2-4x(1080p60) / 4-10x(720p30) | H.264 | Fallback when HEVC is unavailable |
| Other platforms | libx264 | 1x real-time | H.264 | Standard software encoding |
Speed note: the above values are reference ranges from actual testing; actual speed is affected by resolution, frame rate, quality parameters, and system load. In 1080p60 high frame rate scenarios, VideoToolbox is actually about 2-5x real-time (rather than 5-15x), and a 3-hour video takes about 50 minutes.
Screen recording/courseware source bitrate trap (automated since v1.5.0): before compressing, first
ffprobecheck the source filebit_rate. The hardware path (hevc_vt/h264_vt) inhw_detect.pyhas a hardcoded target bitrate of 2000k and ignores the--crf/--maxrateparameter; when the source total bitrate ≤3 Mbps (screen recording/courseware characteristic), the script automatically selects x264 CRF adaptive encoding and prints a notice; high-bitrate sources still use the hardware path,--codecexplicit specification can override automatic selection. CRF adaptive encoding consumes almost no bitrate for static pictures; measured screen recording compression ratio is 80-88% at 12-20x real-time. For manual estimation, a 60-second sample can be used:ffmpeg -ss <中段> -t 60 -i 输入 -c:v libx264 -crf 23 ...look at the sample size to extrapolate the full video.
At startup, the detection result is automatically printed, e.g.:
硬件检测: Apple Silicon (10 核 / 64 GB)
编码器: HEVC VideoToolbox (硬件加速) — 实际 1080p60 约 2-5x 实时
FFmpeg: 9.0 (VideoToolbox 支持: H.264 + HEVC)
Manually specify the encoder:
python3 scripts/compress.py -i <路径> --codec hevc_vt # 强制 HEVC 硬件编码
python3 scripts/compress.py -i <路径> --codec h264_vt # 强制 H.264 硬件编码
python3 scripts/compress.py -i <路径> --codec x264 # 强制软件编码
python3 scripts/compress.py -i <路径> --codec x265 # 软件 HEVC 编码(高压缩)
Available encoders:hevc_vt h264_vt x264 x265 x264_fast
Long Videos and detach Mode
For videos longer than 30 minutes, it is recommended to add --detach Startup:
python3 scripts/compress.py -i <长视频.mp4> --codec hevc_vt --detach
--detach Behavior:
- After the script starts ffmpeg, it immediately returns the PID without waiting for completion
- The ffmpeg process detaches from the script's session group (
start_new_session), so killing the script does not affect encoding - Logs are written to
/tmp/ffmpeg_<视频名>_<时间戳>.log, can be tracked withtail -ftracking
Troubleshooting
ffmpeg binary startup crash (dyld Library not loaded)
Symptom: Immediately after the script starts, it reports "dyld Symbol not found" or "Library not loaded".
Cause: A typical scenario is that after brew upgrade upgrades a dependency library (such as x265), ffmpeg is not relinked; the ffmpeg binary still references symbols from the old version.
Fix:
brew upgrade ffmpeg # 让 ffmpeg 重新链接到新依赖
# 或
brew reinstall ffmpeg # 完全重装
The new script actively checks ffmpeg sanity at startup; when it crashes, it immediately outputs diagnostics and repair commands, no longer silently falling back.
Full stderr log
On failure, the complete ffmpeg log is saved to /tmp/ffmpeg_<视频名>_<时间戳>.log, no longer truncated and losing key diagnostic information.
Hard constraints
- Do not overwrite the original file: The output file always has the suffix added
- Do not silently overwrite old output: If the output file already exists, automatically switch to
_compressed_2and other sequence numbers increment; only--overwriteallows overwriting - Output to the same directory: The trimmed version and the clipped segment directory are both in the same directory as the original file
- Preserve audio quality: Audio uses AAC encoding, default 96k
- Fixed MP4 output: All output files are in MP4 format (hardware encoding HEVC/H.264 + AAC, software encoding x264 + AAC)
- Long videos always use
--detach: Encoding expected to exceed a few minutes must add--detach(ffmpeg detaches from the process group; session timeout/termination does not affect encoding); synchronous mode or terminal-managed background has been tested to be killed, and the incomplete output has no moov atom and is unplayable
Dependencies
| Dependency | Version requirement | Installation method |
|---|---|---|
ffmpeg |
≥ 5.0 (recommended ≥ 7.0 for VideoToolbox -q:v) |
brew install ffmpeg |
Python |
≥ 3.9 (the script is already compatible with the system-provided python3) | System-provided or brew install python |
Working with other skills
- Can work with
universal-media-downloader: compress after downloading the video to save space - Can work with
local-asr/tingwu-asr: transcribe after compression to reduce file transfer time