A collection of free, open-source command-line video utilities for processing, concatenating, and analysing video files.
- Requirements
- motion_cctv — Motion-Only Clip Extraction
- concat_clips — Concatenate Video Clips
- Contributing
- License
- Python 3.8+
- FFmpeg + FFprobe
- OpenCV for Python
pip install opencv-python numpyNote: The standard opencv-python package from PyPI does not include CUDA support.
FFmpeg (Windows recommended via Chocolatey):
choco install ffmpegOr ensure ffmpeg and ffprobe are on your PATH.
Location: motion_cctv/
Extract motion-only clips from security camera (or any other) footage using background subtraction and sustained-motion detection.
Most tools use frame-difference or scene-cut detection, which fails on security/CCTV footage because lighting flickers, compression artefacts, and brief spikes produce hundreds of useless micro-clips. motion_cctv instead answers:
"Has something actually been moving in the scene for long enough to matter?"
- Background subtraction (OpenCV MOG2) with noise suppression
- Requires sustained motion, not single-frame spikes
- Batch processing with optional recursive folder scanning
- Fast FFmpeg cutting (stream copy by default); handles odd audio codecs
- CSV of every detected segment with clip status/errors
- Verbose CLI progress — never appears "stuck"
python motion_cctv/motion_cctv.py /path/to/video_folderOutput:
<video_folder>/motion_output/
├── segments.csv
├── _logs/
│ └── ...
└── VideoName/
└── VideoName_motion_001_12.345-25.678.mp4
| Column | Description |
|---|---|
| source_file | Original video filename |
| clip_index | Index within that video |
| start_seconds | Segment start time |
| end_seconds | Segment end time |
| duration_seconds | Segment length |
| peak_motion_ratio | Max motion intensity during event |
| clip_path | Relative path to output clip |
| status | ok or failed |
| error | Error message if clip failed |
Background subtraction, resizing, colour conversion, blur, and morphology can all run on a CUDA-enabled GPU.
To enable CUDA, build OpenCV from source with -DWITH_CUDA=ON or use a pre-built CUDA package. Verify with:
python -c "import cv2; print('CUDA devices:', cv2.cuda.getCudaEnabledDeviceCount())"python motion_cctv/motion_cctv.py /path/to/videos --hwaccel-decodeSupports NVIDIA NVDEC, Intel Quick Sync, VA-API (Linux), and VideoToolbox (macOS).
Automatically detects GPU encoders: NVENC, Quick Sync, VA-API, VideoToolbox.
python motion_cctv/motion_cctv.py /path/to/videos --no-gpu| Optimisation | Flag | Default | Notes |
|---|---|---|---|
| Frame downscaling | --downscale-width 640 |
ON (640 px) | ~4× speedup, reduces noise |
| Frame skipping | --frame-skip 2 |
OFF | ~2-3× speedup; best for 30+ fps footage |
| HW decode | --hwaccel-decode |
OFF | Requires driver support |
Combined example for maximum throughput:
python motion_cctv/motion_cctv.py /path/to/videos \
--downscale-width 640 \
--frame-skip 2 \
--hwaccel-decode \
--reencode-video| Problem | Adjust |
|---|---|
| Too many false positives | ↑ --min-contour-area, --motion-ratio, --min-motion-frames |
| Missing real motion | ↓ --motion-ratio, --min-contour-area |
| Events split into multiple clips | ↑ --merge-gap, --min-still-frames |
python motion_cctv/motion_cctv.py /path/to/videos --roi 0,0.2,1,0.8Format: x,y,width,height (fractions 0.0–1.0).
| Mode | Flag |
|---|---|
| Video only (default) | (none) |
| Keep audio (re-encode to AAC) | --keep-audio |
| Full re-encode | --reencode-video |
python motion_cctv/test_e2e.pyRequires example footage in example_footage/. The test is skipped when footage is absent.
Location: concat_clips/
Concatenate all video files in a directory into a single output file. Clips are sorted alphabetically by filename by default. Optional --shuffle and --match-seams flags enable random ordering and smooth motion-aware seam transitions.
# Default: alphabetical order
python concat_clips/concat_clips.py /path/to/videos output.mp4
# Shuffle into a random order
python concat_clips/concat_clips.py /path/to/videos output.mp4 --shuffle
# Match seams between clips for smoother transitions (requires OpenCV)
python concat_clips/concat_clips.py /path/to/videos output.mp4 --match-seams
# Shuffle and match seams together
python concat_clips/concat_clips.py /path/to/videos output.mp4 --shuffle --match-seams --seed 42Automatic output naming:
python concat_clips/concat_clips.py --folder /path/to/videos
# → /path/to/videos.mp4| Option | Description |
|---|---|
--shuffle |
Shuffle clips into a random order (default: alphabetical) |
--seed |
Random seed for reproducible shuffling (used with --shuffle) |
--match-seams |
Match seams between clips using motion-aware frame comparison (requires OpenCV) |
--haystack-duration |
Seconds to search for best match (used with --match-seams, default: 1.0) |
--haystack-skip |
Seconds to skip at start of each clip before searching (default: 0.0) |
--folder |
Input folder; output saved as <folder>.mp4 |
--no-recursive |
Don't search subdirectories (default: recursive) |
--fps |
Output framerate (H.264 bitstream remux) |
--ffmpeg / --ffprobe |
Custom executable paths |
- Extract the last 2 consecutive frames of the preceding clip ("needle pair").
- Sample pairs of consecutive frames in the first N seconds of the next clip ("haystack").
- Pick the pair with the lowest combined MSE — this captures motion direction and prevents sudden reversals.
- Trim the next clip to start at that best-matching frame.
- Alphabetical sort by filename (default)
- Random shuffle with optional reproducible seed (
--shuffle,--seed) - Motion-aware seam matching for smooth transitions (
--match-seams) - Recursive scanning across subdirectories (default)
- Auto-detects codec, resolution, and framerate from the first clip
- Smart re-encoding for clips that don't match
- Supports mp4, avi, mkv, mov, flv, wmv, webm, m4v, mpg, mpeg
python -m unittest concat_clips.test_concat_clips -v
python -m unittest concat_clips.test_concat_seams -vPull requests welcome for:
- Additional detectors (optical flow, object tracking)
- Performance improvements
- Better defaults for specific camera types
- New video utilities
MIT