# Bulk Video Processor
An interactive command-line tool for bulk video processing, resolution conversion, and optimization. Built with a professional terminal UI that guides users through each step of the processing pipeline.
Features Overview
Core Features
Bulk Video Processing
Process entire directories of videos with optional subdirectory support:
def process_directory(source_dir: str, output_dir: str, settings: dict):
video_extensions = ['.mp4', '.avi', '.mov', '.mkv', '.wmv', '.flv', '.webm', '.m4v']
for root, dirs, files in os.walk(source_dir):
for file in files:
if any(file.lower().endswith(ext) for ext in video_extensions):
process_video(os.path.join(root, file), output_dir, settings)Resolution Presets
| Preset | Resolution | Use Case |
|---|---|---|
| 4K | 3840×2160 | Ultra HD displays |
| 2K | 2560×1440 | QHD monitors |
| 1080p | 1920×1080 | Full HD streaming |
| 720p | 1280×720 | Mobile/HD |
| 480p | 854×480 | SD, low bandwidth |
| 360p | 640×360 | Mobile, minimal bandwidth |
| 1K | 1024×576 | Custom (as requested) |
Codec Support
CODEC_OPTIONS = {
"H.264 (MP4)": {
"extension": ".mp4",
"video_codec": "libx264",
"audio_codec": "aac"
},
"H.265 (MP4)": {
"extension": ".mp4",
"video_codec": "libx265",
"audio_codec": "aac"
},
"VP9 (WebM)": {
"extension": ".webm",
"video_codec": "libvpx-vp9",
"audio_codec": "libopus"
}
}Quality Profiles
| Profile | CRF | FFmpeg Preset | Description |
|---|---|---|---|
| High Quality | 18 | slow | Best quality, larger files |
| Balanced | 23 | medium | Good quality/size balance |
| High Compression | 28 | fast | Smaller files, acceptable quality |
| Ultra Compression | 32 | veryfast | Smallest files, lower quality |
CRF (Constant Rate Factor): Lower = better quality. Range 0-51.
Video Filters
def apply_filters(video_path: str, filter_settings: dict) -> str:
filters = []
if filter_settings.get('denoise'):
filters.append('nlmeans=s=10')
if filter_settings.get('sharpen'):
filters.append('unsharp=5:5:1.0:5:5:0.0')
if filter_settings.get('brightness'):
filters.append(f'eq=brightness={filter_settings["brightness"]}')
if filter_settings.get('contrast'):
filters.append(f'eq=contrast={filter_settings["contrast"]}')
return ','.join(filters)Two-Pass Encoding
Optional two-pass encoding for maximum quality:
# First pass: Analyze video
ffmpeg -i input.mp4 -pass 1 -f null -y
# Second pass: Encode with analysis data
ffmpeg -i input.mp4 -pass 2 output.mp4Interactive CLI
The tool uses Rich for professional terminal UI:
from rich.console import Console
from rich.progress import Progress, SpinnerColumn, BarColumn
console = Console()
console.print(Panel.fit(
"[bold cyan]Aatmanova Bulk Video Processor[/bold cyan]\n"
"by Bhargab Pratim Sarma",
border_style="cyan"
))User Workflow
--- Step 1: Select Source Folder ---
Enter the path to your source video folder: /Users/videos/raw
--- Step 2: Configure Output ---
Save output to default location? (/Users/videos/raw-Processed) [Y/n]:
--- Step 3: Choose Target Resolution ---
┏━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Resolution ┃ Dimensions ┃ Use Case ┃
┡━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ 4K │ 3840x2160 │ Ultra HD, high-end │
│ 1080p │ 1920x1080 │ Full HD, standard │
│ 720p │ 1280x720 │ HD, mobile devices │
└────────────┴───────────────┴──────────────────────────┘
Select target resolution: 1080p
--- Step 6: Additional Options ---
Maintain aspect ratio when scaling? [Y/n]: Y
Use two-pass encoding? [y/N]: n
Maintain original subfolder structure? [Y/n]: YProgress Tracking
with Progress(
SpinnerColumn(),
TextColumn("[progress.description]{task.description}"),
BarColumn(),
TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
console=console
) as progress:
task = progress.add_task("Processing videos...", total=len(videos))
for video in videos:
process_video(video)
progress.update(task, advance=1)FFmpeg Integration
import ffmpeg
def convert_video(input_path: str, output_path: str, settings: dict):
stream = ffmpeg.input(input_path)
# Resolution scaling
if settings['resolution']:
stream = stream.filter('scale',
settings['resolution']['width'],
settings['resolution']['height'],
force_original_aspect_ratio='decrease'
)
# Video codec and quality
stream = ffmpeg.output(
stream,
output_path,
vcodec=settings['codec'],
crf=settings['crf'],
preset=settings['preset'],
acodec=settings.get('audio_codec', 'aac')
)
ffmpeg.run(stream, overwrite_output=True)Processing Log
Automatically generates processing_log.json:
{
"timestamp": "2025-09-19T17:30:00",
"settings": {
"source": "/path/to/videos",
"output": "/path/to/output",
"resolution": "1080p",
"codec": "H.264",
"quality": "Balanced"
},
"results": [
{
"input": "video1.mp4",
"output": "video1_processed.mp4",
"original_size": "150MB",
"output_size": "45MB",
"compression": "70%",
"duration": "2m 30s"
}
]
}Hardware Acceleration
Optional GPU acceleration for NVIDIA:
# Replace CPU codecs with GPU equivalents
GPU_CODECS = {
"libx264": "h264_nvenc",
"libx265": "hevc_nvenc"
}
if use_gpu and has_nvidia_gpu():
video_codec = GPU_CODEC_MAPPING.get(video_codec, video_codec)Prerequisites
FFmpeg Installation
Windows:
- Download from gyan.dev/ffmpeg/builds
- Extract to
C:\ffmpeg - Add
C:\ffmpeg\binto PATH
macOS:
brew install ffmpegLinux:
sudo apt install ffmpegVerify installation:
ffmpeg -versionPython Setup
python -m venv venv
source venv/bin/activate # or venv\Scripts\activate on Windows
pip install -r requirements.txtPyInstaller Packaging
Create standalone executable:
pip install pyinstaller
pyinstaller --onefile --name "BulkVideoProcessor" bulk_video_processor.pyOutput: dist/BulkVideoProcessor.exe
Note: Users still need FFmpeg installed on their system.
File Organization
Input/
├── videos/
│ ├── movie1.mp4
│ ├── movie2.avi
│ └── subfolder/
│ └── movie3.mov
Output/
├── videos-Processed/
│ ├── movie1_processed.mp4
│ ├── movie2_processed.mp4
│ ├── subfolder/
│ │ └── movie3_processed.mp4
│ └── processing_log.jsonPerformance Tips
- Use SSD: Faster I/O for source and output
- More RAM: Better caching (8GB+ recommended)
- Multi-core CPU: FFmpeg uses multiple cores
- Faster presets: Use
fastorveryfastfor bulk - Don't upscale: Only downscale, upscaling doesn't improve quality
Use Cases
- Content creators: Batch convert recordings to upload-friendly formats
- Archival: Compress legacy video collections
- Mobile: Downscale 4K footage to 720p for phone viewing
- Web: Convert to WebM for web embedding
- Backup: Convert to space-saving H.265
Architecture Feedback
Spotted a potential optimization or antipattern? Let me know.