Black-frame video trimmer: detect long black + silent stretches and remove all but the first moment of each.
Project description
bfvt — black-frame video trimmer
Scan a video, find long stretches that are simultaneously black and silent, and remove all but the first moment of each — then write a re-encoded, trimmed file. Built for chopping the dead air out of recordings: the leader/trailer black, the gap between segments, the "I forgot to stop the screen recorder" tail.
Tiny stray bright pixels (codec ringing, a dead-pixel speck, a faint watermark)
are still treated as black, so a frame doesn't get disqualified just because a
handful of pixels aren't perfectly #000000.
How it decides what to cut
- Black detection (OpenCV). Frames are sampled (default 10 fps). A frame counts as black when the fraction of pixels brighter than a luma threshold is at or below a small ratio (default 0.2%) — that ratio is the "ignore stray pixels" knob.
- Silence detection (ffmpeg
silencedetect). Audio below a noise floor (default −30 dB) is silence. Videos with no audio track are treated as wholly silent, so black detection alone drives the cut. - Interval algebra (pure, deterministic). The black intervals are
intersected with the silent intervals. Each overlapping run that lasts at
least
--min-duration(default 5 s) is trimmed, keeping the first--keep-headseconds (default 0.25 s) so a hard chapter cut doesn't become a jarring jump. Everything else in the run is removed. - Re-encode (ffmpeg). The kept segments are concatenated via a
trim/atrim+concatfiltergraph and re-encoded (libx264 + AAC).
Given the same input and flags, the output is deterministic.
Install
pip install .
# or, for development + tests:
pip install -e ".[test]"
Requires ffmpeg and ffprobe on PATH. OpenCV is pulled in via
opencv-python-headless.
Usage
# Trim, writing alongside the input as <name>.trimmed.mp4
bfvt input.mp4
# Choose the output and the threshold
bfvt input.mp4 -o clean.mp4 --min-duration 5 --keep-head 0.25
# See what WOULD be cut without re-encoding
bfvt input.mp4 --dry-run
# Trim on darkness alone (ignore audio)
bfvt input.mp4 --ignore-audio
Key options
| Flag | Default | Meaning |
|---|---|---|
--min-duration SEC |
5.0 |
Minimum black+silent run before anything is trimmed |
--keep-head SEC |
0.25 |
Seconds at the start of each run to preserve |
--luma-threshold N |
32 |
0–255 luma above which a pixel is "bright" |
--bright-ratio R |
0.002 |
Max fraction of bright pixels for a frame to still be black |
--sample-fps FPS |
10 |
Frame sampling rate for black detection |
--noise-db DB |
-30 |
Audio below this dB is silence |
--ignore-audio |
off | Trim on darkness only |
--crf / --preset |
18 / medium |
libx264 quality/speed |
--dry-run |
off | Report cuts, write nothing |
Library
from bfvt import TrimConfig, analyze, run
cfg = TrimConfig(min_duration=5.0, keep_head=0.25)
res = analyze("input.mp4", cfg) # inspect res.black / res.silent / res.cuts
run("input.mp4", "out.mp4", cfg) # do the trim
The interval logic is exposed directly (merge_segments,
intersect_segments, black_silent_cuts, keep_segments_from_cuts) and is
pure/dependency-free.
Tests
pytest -q # all tests (integration generates a real clip)
pytest -q -m "not integration" # pure unit tests only, no ffmpeg/OpenCV needed
The unit tests cover the interval algebra, the black-frame pixel classifier
(including the stray-pixel tolerance), the silencedetect log parser, and the
ffmpeg filtergraph builder. The integration test synthesizes a
blue → black/silent → green clip with ffmpeg, runs the whole pipeline, and
asserts the black stretch is detected and removed.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file bfvt-0.1.0.tar.gz.
File metadata
- Download URL: bfvt-0.1.0.tar.gz
- Upload date:
- Size: 21.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8b06cabdfa0949b98b46ab231f9d3b122e55824f8d1b8fac6fb600e78c3f3225
|
|
| MD5 |
f830a10111d0315332948ff5f3b8921e
|
|
| BLAKE2b-256 |
37707e95a2dbbdcf17bb8c5e737691673c8f46f33fa96df1825e32537afdc510
|
File details
Details for the file bfvt-0.1.0-py3-none-any.whl.
File metadata
- Download URL: bfvt-0.1.0-py3-none-any.whl
- Upload date:
- Size: 16.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ad254b4f34c923237c5eaa3219402b8ebcdd6cb32fda6997847c64ed7d7b695c
|
|
| MD5 |
1dde197634029e837a359838ef3e5f0f
|
|
| BLAKE2b-256 |
ad23c029f710dc65e205b906a5b59ed78f480b52425c9c521ac018493e552892
|