| checks | ||
| launchers | ||
| profiles | ||
| tmp | ||
| utils | ||
| web | ||
| .gitignore | ||
| config.py | ||
| qc_module.py | ||
| README.md | ||
| requirements.txt | ||
| setup.sh | ||
H&M Video QC Tool
Standalone video quality control tool for H&M marketing assets. Validates videos against technical specifications, naming conventions, and content requirements.
Features
- Web Interface: Modern Flask-based web UI with Microsoft SSO authentication
- Multi-Page Wizard: Upload → Configure → Progress → Results workflow
- Real-Time Progress: Server-Sent Events for live QC updates
- Video Parsing: Extract comprehensive metadata (codec, resolution, FPS, bitrate, duration, audio)
- Filename Validation: Parse H&M video naming conventions
- Technical Validation: Validate codec, bitrate, frame rate, audio specifications
- Dimension Validation: Verify resolution matches filename (supports aspect ratios like 1x1, 16x9)
- Duration Validation: Verify duration matches filename
- AI-Powered Censorship Check: Frame-by-frame analysis for CEN market videos
- HTML Reports: Beautiful, interactive reports with H&M black/yellow styling
- Authentication: Microsoft Azure AD SSO integration
- CLI Support: Command-line interface for automated workflows
Project Structure
hm_qc_video/
├── qc_module.py # Core QC orchestrator
├── config.py # Environment configuration
├── requirements.txt # Python dependencies
├── .env # Environment variables (API keys, Azure AD config)
├── checks/ # QC check modules
│ ├── video_parse.py
│ ├── video_filename_parse.py
│ ├── video_technical_check.py
│ ├── video_dimension_check.py
│ ├── video_duration_check.py
│ ├── video_censorship.py
│ └── analyze_with_gpt.py
├── web/ # Web interface (Flask)
│ ├── app.py # Flask app initialization
│ ├── routes.py # Route handlers
│ ├── qc_runner.py # Background QC execution with SSE
│ ├── auth_middleware.py # Azure AD authentication middleware
│ ├── jwt_validator.py # JWT token validation
│ ├── templates/ # HTML templates
│ │ ├── base.html # Base template with H&M styling
│ │ ├── login.html # MSAL login page
│ │ ├── upload.html # File upload page
│ │ ├── configure.html # Check selection page
│ │ ├── progress.html # Real-time progress page
│ │ └── results.html # Results display page
│ ├── static/ # CSS and JavaScript
│ │ ├── css/styles.css
│ │ └── js/ # Client-side scripts
│ └── uploads/ # Temporary file uploads
├── profiles/
│ └── HM_video.json # Video QC profile
├── launchers/
│ ├── video_launcher_CLI.py # CLI entry point
│ └── web_launcher.py # Web server entry point
├── utils/
│ ├── report.py # HTML report generator (CLI)
│ └── web_report.py # HTML report generator (Web styling)
└── tmp/ # Working directory (created automatically)
Installation
Prerequisites
- Python 3.8+
- FFmpeg (must be installed and available in PATH)
Install FFmpeg
macOS:
brew install ffmpeg
Linux (Ubuntu/Debian):
sudo apt-get update
sudo apt-get install ffmpeg
Windows: Download from https://ffmpeg.org/download.html and add to PATH
Install Python Dependencies
- Create and activate virtual environment:
python3 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
- Install dependencies:
pip install -r requirements.txt
- Set up environment variables in
.envfile:
# OpenAI API key for AI-powered checks
OPENAI_API_KEY=your-api-key-here
# Environment mode (dev or production)
HM_VIDEO_QC_ENV=dev
# Azure AD / MSAL Authentication Configuration
AZURE_TENANT_ID=e519c2e6-bc6d-4fdf-8d9c-923c2f002385
AZURE_CLIENT_ID=9079054c-9620-4757-a256-23413042f1ef
# Flask Security Configuration
FLASK_ENV=development
SECRET_KEY=your-secret-key-here-change-in-production
# Port Configuration:
# Local dev: Port 7183 (http://localhost:7183 registered in Azure AD)
# Production: Port 5102
Usage
Web Interface (Recommended)
The web interface provides an intuitive multi-page wizard with real-time progress updates and Microsoft SSO authentication.
Local Development (Port 7183)
# Start web server with authentication testing
python launchers/web_launcher.py --debug
# Access: http://localhost:7183
Features:
- Microsoft SSO login (http://localhost:7183 registered in Azure AD)
- Drag-and-drop file upload
- Interactive check selection
- Real-time progress updates with Server-Sent Events
- Beautiful H&M-styled reports (black background, yellow accents)
- User info display with logout functionality
Production Deployment (Port 5102)
# Start production web server
python launchers/web_launcher.py --host 0.0.0.0 --port 5102
# Access: http://your-server:5102
Workflow:
- Login → Sign in with Microsoft account
- Upload → Drag and drop video file (up to 5GB)
- Configure → Select which QC checks to run
- Progress → Watch real-time check execution
- Results → View interactive HTML report
CLI Interface (For Automation)
For automated workflows and batch processing, use the command-line interface.
Basic Usage
python launchers/video_launcher_CLI.py <path_to_video> <path_to_report>
Example
# Run QC on a video file
python launchers/video_launcher_CLI.py /path/to/video.mp4 ./reports/video_report.html
Supported Video Formats
- MP4 (.mp4)
- MOV (.mov)
- AVI (.avi)
- MKV (.mkv)
- WebM (.webm)
- FLV (.flv)
- WMV (.wmv)
- M4V (.m4v)
Configuration
Environment Variables
HM_VIDEO_QC_ENV: Set todevorproduction(default:production)OPENAI_API_KEY: Required for AI-powered checks (GPT-4o)
Environments
Development (dev):
- Uses relative paths from repository root
- Working directory:
./tmp/HM_video_working - Reports directory:
./tmp/reports
Production (production):
- Uses absolute paths
- Working directory:
/tmp/HM_video_working - Reports directory:
/opt/hm_qc_video/reports
Profile Configuration
Edit profiles/HM_video.json to customize checks and thresholds:
{
"id": "video_technical_check",
"script": "checks.video_technical_check",
"config": {
"allowed_codecs": ["h264", "h265"],
"allowed_frame_rates": [24, 25, 30, 60],
"min_bitrate_mbps": {"1920x1080": 5},
"audio_codec": ["aac"]
}
}
Authentication
Microsoft Azure AD SSO
The web interface uses Microsoft Azure AD for authentication via MSAL (Microsoft Authentication Library).
Authentication Flow:
- User accesses protected route → Redirected to
/login - Clicks "Sign in with Microsoft" → MSAL popup opens
- User authenticates with Microsoft account
- ID token sent to backend → Validated with Azure AD JWKS
- httpOnly cookie set → User redirected to main app
- User info (name, email) displayed in header
Security Features:
- ✅ httpOnly cookies prevent XSS token theft
- ✅ Server-side JWT validation with Azure AD JWKS
- ✅ Token expiration checking (24-hour max)
- ✅ Tenant and audience validation
- ✅ SameSite=Lax for CSRF protection
- ✅ HTTPS enforcement in production
Azure AD Configuration:
- Tenant ID:
e519c2e6-bc6d-4fdf-8d9c-923c2f002385(H&M tenant) - Client ID:
9079054c-9620-4757-a256-23413042f1ef(shared with ai_qc) - Registered Redirect URIs:
- Local:
http://localhost:7183 - Production: Your production server URL
- Local:
Cookie Name: hm_video_qc_auth_token
QC Checks
1. Video Parse
Extracts video metadata using FFmpeg:
- Video codec, resolution, frame rate, bitrate
- Audio codec, sample rate, channels, bitrate
- Duration, container format
- Thumbnail extraction
2. Filename Parse
Parses H&M video naming conventions:
- Language/market code (e.g.,
en-GB,CEN,GEN) - Campaign number
- Duration (e.g.,
30s) - Resolution (e.g.,
1920x1080) - Frame rate (e.g.,
30fps)
3. Technical Check
Validates technical specifications:
- Video codec (H.264, H.265)
- Container format (MP4, MOV)
- Frame rate (23.976, 24, 25, 29.97, 30, 50, 60 fps)
- Video bitrate (min/max by resolution)
- Audio codec (AAC, PCM)
- Audio sample rate (48kHz ±1kHz)
- Audio bitrate (128-320 kbps)
- Audio channels (stereo, mono)
4. Dimension Check
Validates resolution matches filename expectations
5. Duration Check
Validates duration matches filename (±2 seconds tolerance)
6. Censorship Check (Filename-based)
AI-powered frame-by-frame analysis using DSPy + GPT-4o:
Logic based on filename suffix:
- ❌ No
_GENor_CENsuffix → Check is skipped (not applicable) - ❌ Filename contains
_GEN→ Check is skipped (censorship not required) - ✅ Filename contains
_CEN→ AI censorship checks are conducted
What it validates:
- Body coverage requirements (arms, legs, midriff)
- Analyzes all extracted video frames
- Requires 100% compliance across all frames
- Requires training data in
./supporting/censorship_trainset/
Examples:
AT_de_4116A_Halloween_30s_1920x1080_GEN.mp4→ Skipped (_GEN suffix)AT_de_4116A_Halloween_30s_1920x1080_CEN.mp4→ Runs (_CEN suffix)AT_de_4116A_Halloween_30s_1920x1080.mp4→ Skipped (no suffix)
Training Data for Censorship Check
For the censorship check to work, you need training images in:
./supporting/censorship_trainset/
├── example1-C.png # Censored example
├── example1-U.png # Uncensored example
├── example2-C.png
├── example2-U.png
└── ...
Filename convention:
-Csuffix: Censored (compliant)-Usuffix: Uncensored (non-compliant)
Reports
HTML reports include:
- Summary statistics (total checks, passed, failed, skipped)
- Detailed results for each check
- Color-coded status badges
- Collapsible sections for easy navigation
- Technical metadata tables
Troubleshooting
FFmpeg not found
Error: FFmpeg not found in PATH
Solution: Install FFmpeg and ensure it's in your system PATH
OpenAI API key missing
Error: OpenAI API key not found
Solution: Set the OPENAI_API_KEY in your .env file
Module import errors
ModuleNotFoundError: No module named 'checks'
Solution: Run from the project root directory, not from subdirectories
Authentication errors
{
"authenticated": false,
"error": "Authentication required",
"message": "Token validation failed"
}
Solution:
- Ensure you're accessing the correct port (7183 for local, 5102 for production)
- Clear browser cookies and try logging in again
- Verify Azure AD credentials in
.envfile are correct - Check that redirect URI is registered in Azure AD
Port already in use
Error: Address already in use
Solution:
- Check if another application is using the port
- Kill the process:
lsof -ti:7183 | xargs kill -9 - Or use a different port:
python launchers/web_launcher.py --port 8000
Login popup blocked
Solution: Allow popups in your browser for localhost:7183 or your production domain
Development
Running in Development Mode
Web Interface:
# Runs on http://localhost:7183 with authentication
python launchers/web_launcher.py --debug
CLI:
export HM_VIDEO_QC_ENV=dev
python launchers/video_launcher_CLI.py test_video.mp4 ./tmp/reports/report.html
Adding New Checks
- Create check module in
checks/directory - Implement
run_check(config, context, check_id)function - Return standardized result dictionary:
{
"status": "passed|error|skipped",
"details": {...},
"error_message": "..." (if error)
}
- Add check to
profiles/HM_video.json - Check will automatically appear in web interface configuration page
Web Interface Development
Key Files:
web/routes.py- Add new routesweb/templates/- HTML templates with Jinja2web/static/css/styles.css- H&M black/yellow stylingweb/qc_runner.py- Background job execution with SSE
Adding New Routes:
@app.route('/your-route')
@auth.require_auth
def your_route():
return render_template('your_template.html', user=g.user)
H&M Styling Guide:
- Background:
#000000(black) - Accent:
#FFC407(yellow) - Font: Montserrat (Google Fonts)
- Borders:
#333333(dark gray)
Dependencies
Core:
- Flask 3.0.0 - Web framework
- PyJWT 2.8.0 - JWT token validation
- Requests 2.31.0 - HTTP requests for JWKS
Video Processing:
- FFmpeg-python, OpenCV, MoviePy
- Pillow for image processing
- Scenedetect for scene analysis
AI/ML:
- OpenAI 1.60.0 (GPT-4o)
- DSPy-AI 2.5.43
License
Internal H&M tool - All rights reserved
Support
For issues or questions, contact the development team.