A pluggable post-processing pipeline for security camera videos. Recursively scans directories of video files and applies a chain of plugins: frame extraction via ffmpeg, animated GIF generation, AWS Rekognition tagging, and HTML summary pages. Also handles file movement and remuxing from camera output folders to a date-organized archive.
- Python 3.10+
- ffmpeg — frame extraction and video remuxing
- AWS credentials configured for Rekognition (see Configuration below)
Frame resizing and animated GIF generation are handled natively by Pillow, which is included in requirements.txt.
chmod +x setup_venv.sh
./setup_venv.shThis checks for Python 3.10+, creates a .venv virtual environment, and installs all dependencies.
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txtCopy the sample settings file and fill in your AWS credentials:
cp settings-sample.yml settings.ymlEdit settings.yml with your values:
access_key_id: YOUR_ACCESS_KEY
secret_access_key: YOUR_SECRET_KEY
region: us-west-2
flagged_tags:
- human
- humans
- person
- people
stopwords:
- plant
- building
# ... additional tags to ignoreflagged_tags— labels that indicate high-importance detections (e.g., people)stopwords— labels treated as background noise and excluded from important tags
source .venv/bin/activate
python main.py <input_directory> <output_directory>The pipeline:
- Moves and remuxes stable
.mp4files frominput_directoryinto date-organized subfolders underoutput_directory - Scans
output_directoryfor.mp4files, extracts frames, and runs:- Tagger — sends frames to AWS Rekognition, writes
.jsonmetadata - GifMaker — generates
.giftimelapse thumbnails - Summarizer — produces
index.htmlsummary pages per directory
- Tagger — sends frames to AWS Rekognition, writes
A process guard prevents multiple instances from running simultaneously.
Run the processor in a Docker container with all dependencies (Python 3.10+, ffmpeg with H.264/HEVC) pre-installed.
- Docker Engine or Docker Desktop must be installed and running.
| Target | Description |
|---|---|
make docker-build |
Build the Docker container image |
make docker-test |
Run tests inside the Docker container |
make docker-run |
Run the processor inside the Docker container |
make docker-debug |
Launch an interactive bash shell in the Docker container |
The container uses bind mounts to access host files without rebuilding the image:
| Host Path | Container Path | Mode | Purpose |
|---|---|---|---|
settings.yml |
/app/settings.yml |
read-only | Configuration file |
input/ |
/media/input |
read-only | Input media directory |
output/ |
/media/output |
read-write | Output media directory |
Override these on the command line (e.g., make docker-run DOCKER_INPUT_DIR=/my/videos):
| Variable | Default | Description |
|---|---|---|
DOCKER_IMAGE_NAME |
securitycam-processor |
Image tag used for build and run |
DOCKER_CONFIG_PATH |
$(CURDIR)/settings.yml |
Host path to settings YAML |
DOCKER_INPUT_DIR |
$(CURDIR)/input |
Host path to input media directory |
DOCKER_OUTPUT_DIR |
$(CURDIR)/output |
Host path to output media directory |
# Build the image
make docker-build
# Run the test suite in the container
make docker-test
# Process media files
make docker-run
# Pass additional arguments to main.py
make docker-run ARGS="--dry-run"
# Open an interactive shell for debugging
make docker-debugSecurityCamProcessor.Python/
├── main.py # CLI entry point and process guard
├── scanner.py # Core engine, Callback/DirectoryCallback base classes
├── gifmaker.py # GIF timelapse plugin
├── tagger.py # AWS Rekognition tagging plugin
├── metadata.py # Filename timestamp extraction
├── summarizer.py # HTML summary generation plugin
├── mover.py # File movement and remuxing
├── settings-sample.yml # Sample configuration
├── requirements.txt # Python dependencies
├── setup_venv.sh # Virtual environment setup script
├── mypy.ini # mypy strict mode configuration
├── py.typed # PEP 561 type hint marker
├── archive.sh # Archive older recordings to long-term storage
├── previews/ # Live camera preview system
│ ├── GenPreviews.sh # Capture RTSP thumbnails
│ ├── index.html # Preview grid page
│ ├── start_web_server.sh # Start nginx Docker container
│ └── config-example.sh # Sample camera configuration
└── tests/ # Test suite (pytest + Hypothesis)
source .venv/bin/activate
pytestmypy --config-file mypy.ini *.pyAll modules are fully type-annotated and pass mypy --strict.
Move older date-stamped recording folders to a long-term archive location, keeping the five most recent:
bash archive.sh <recordings_folder> <archive_folder>Capture live thumbnails from RTSP camera streams and serve them via a web page:
- Copy
previews/config-example.shtopreviews/config.shand configure your cameras - Run
previews/GenPreviews.shto capture thumbnails - Run
previews/start_web_server.shto serve the preview page on port 8080