# Quality Checking Feature ## Overview encoderPro now includes intelligent quality analysis that detects source video quality and warns you if encoding will degrade quality to a noticeable degree. This prevents accidental quality loss when re-encoding high-quality source material. --- ## Key Features ### 1. **Automatic Quality Detection** - Analyzes source video bitrate, resolution, codec, and FPS - Calculates quality score (0-100) based on bitrate per pixel - Detects HDR content - Accounts for codec efficiency (H.265 vs H.264 vs AV1) ### 2. **Pre-Encoding Quality Comparison** - Estimates target encoding bitrate based on your CRF settings - Compares source quality to estimated target quality - Warns if quality drop exceeds configurable thresholds - Provides detailed quality metrics for decision making ### 3. **Processed File Tracking** - Database tracks all processed files - Automatically skips already-encoded files on re-runs - Maintains processing history with quality metrics - Supports manual reset for re-processing ### 4. **Configurable Behavior** - Enable/disable quality checking - Adjustable warning and error thresholds - Option to skip degraded files automatically - User prompts for manual confirmation --- ## Configuration Add this section to your `config.yaml`: ```yaml quality_check: # Enable pre-encoding quality analysis enabled: true # Warning threshold - warn if quality will drop by this many points (0-100 scale) warn_threshold: 10.0 # Error threshold - fail/skip if quality will drop by this many points error_threshold: 20.0 # Automatically skip files where encoding would degrade quality skip_on_degradation: false # Prompt user for confirmation when warnings detected (CLI only) prompt_on_warning: true ``` ### Configuration Options Explained | Option | Type | Default | Description | |--------|------|---------|-------------| | `enabled` | boolean | `true` | Enable/disable quality checking entirely | | `warn_threshold` | float | `10.0` | Quality score drop that triggers a warning | | `error_threshold` | float | `20.0` | Quality score drop that triggers an error | | `skip_on_degradation` | boolean | `false` | Auto-skip files with quality degradation | | `prompt_on_warning` | boolean | `true` | Ask user for confirmation on warnings | --- ## How Quality Scores Work ### Quality Score (0-100) The quality checker calculates a score based on **bits per pixel per frame**: ``` Quality Score = f(bitrate, resolution, fps, codec_efficiency) ``` **Score Ranges:** - **95-100:** Near-lossless / Exceptional quality - **85-95:** Excellent / Archival quality - **70-85:** Good / Visually transparent - **50-70:** Acceptable / Minor compression visible - **0-50:** Poor / Heavy compression artifacts ### Codec Efficiency Multipliers The quality checker accounts for codec efficiency: | Codec | Multiplier | Notes | |-------|------------|-------| | AV1 | 1.8x | Most efficient codec | | H.265/HEVC | 1.5x | ~50% better than H.264 | | H.264/AVC | 1.0x | Baseline reference | | MPEG-2 | 0.5x | Older, less efficient | | MPEG-4 | 0.7x | Older codec | **Example:** A video at 5 Mbps H.265 has similar quality to 7.5 Mbps H.264. ### Bits Per Pixel Ranges | BPP Range | Quality | Typical Use Case | |-----------|---------|------------------| | > 0.5 | Near-lossless (95-100) | Professional archival | | 0.3 - 0.5 | Excellent (85-95) | High-quality archival | | 0.2 - 0.3 | Good (70-85) | **Sweet spot for home media** | | 0.1 - 0.2 | Acceptable (50-70) | Streaming services | | < 0.1 | Poor (0-50) | Heavy compression | --- ## Usage Examples ### Example 1: Analyze Video Quality ```bash python3 quality_checker.py /movies/example.mkv ``` **Output:** ``` Video Quality Analysis: Resolution: 1920x1080 Bitrate: 8.5 Mbps Codec: h264 FPS: 23.98 HDR: No Quality Score: 72.3/100 ``` ### Example 2: Check Before Encoding ```python from quality_checker import QualityChecker from pathlib import Path checker = QualityChecker() # Define your encoding profile profile = { 'encoder': 'nvidia_nvenc_h265', 'quality': 21 # CRF value } # Check quality before encoding result = checker.check_before_encode( Path('/movies/example.mkv'), profile, warn_threshold=10.0, error_threshold=20.0 ) if result['ok']: print("✅ Safe to encode") elif result['warning']: print(f"⚠️ Warning: {result['message']}") elif result['error']: print(f"❌ Error: {result['message']}") ``` ### Example 3: Batch Analysis See `example_quality_check.py` for comprehensive examples including: - Single file analysis - Quality degradation checks - Comprehensive pre-encode checks - Batch directory analysis --- ## Understanding Quality Degradation ### What Causes Quality Degradation? Encoding can degrade quality when: 1. **Source is already high quality** - Source: 95/100 (near-lossless BluRay rip at 25 Mbps) - Target: 75/100 (H.265 CRF 21 at 8 Mbps) - **Drop:** 20 points ⚠️ 2. **Target bitrate is too low** - Source: 4K movie at 40 Mbps - Target: 4K at 10 Mbps (too aggressive) - **Result:** Visible compression artifacts 3. **Re-encoding already compressed content** - Source: Web-DL already at CRF 23 - Target: Re-encode at CRF 21 - **Result:** Quality loss from generation loss ### When to Proceed Despite Warnings **Safe to proceed:** - Source quality 50-70 (already compressed) - Quality drop < 10 points - Testing settings on sample files - Source is a screen recording or low-quality capture **Consider skipping:** - Source quality > 90 (near-lossless) - Quality drop > 20 points - Archival content you want to preserve - BluRay remuxes or untouched sources --- ## Real-World Examples ### Example 1: BluRay Remux (Skip Recommended) ``` Source Quality Analysis: Resolution: 1920x1080 Bitrate: 28.5 Mbps (H.264) Quality Score: 96/100 (Near-lossless) Target Settings (CRF 21 H.265): Estimated Bitrate: 7.2 Mbps Target Quality: 73/100 ⚠️ WARNING: Quality will drop by 23 points ❌ Recommendation: SKIP - Source is too high quality ``` **Action:** Skip encoding or use CRF 18-19 for archival quality. --- ### Example 2: Web-DL (Safe to Encode) ``` Source Quality Analysis: Resolution: 1920x1080 Bitrate: 6.2 Mbps (H.264) Quality Score: 68/100 (Good) Target Settings (CRF 21 H.265): Estimated Bitrate: 5.8 Mbps Target Quality: 71/100 ✅ OK: Quality will improve by 3 points ✅ Recommendation: PROCEED - Safe to encode ``` **Action:** Proceed with encoding. Will remove subtitles without quality loss. --- ### Example 3: Already Encoded (Warning) ``` Source Quality Analysis: Resolution: 1920x1080 Bitrate: 4.8 Mbps (H.265) Quality Score: 65/100 (Acceptable) Target Settings (CRF 21 H.265): Estimated Bitrate: 5.2 Mbps Target Quality: 68/100 ⚠️ WARNING: Re-encoding already compressed H.265 ⚠️ Recommendation: Consider CRF 19-20 to avoid generation loss ``` **Action:** Consider lower CRF or skip. Source is already H.265. --- ### Example 4: Low Quality Source (Safe) ``` Source Quality Analysis: Resolution: 1920x1080 Bitrate: 2.8 Mbps (H.264) Quality Score: 52/100 (Acceptable) Target Settings (CRF 21 H.265): Estimated Bitrate: 5.8 Mbps Target Quality: 71/100 ✅ OK: Quality will improve by 19 points ✅ Recommendation: PROCEED - Encoding will improve quality ``` **Action:** Proceed. H.265 encoding will improve perceived quality. --- ## HDR Content Detection The quality checker automatically detects HDR content: ### HDR Detection Criteria 1. **Transfer characteristics:** - SMPTE 2084 (HDR10) - ARIB STD-B67 (HLG) 2. **Color primaries:** - BT.2020 color space 3. **Metadata tags:** - Any tag containing "HDR" ### HDR Warning If HDR content is detected and `hdr_handling` is not set to `preserve`: ``` ⚠️ HDR content detected but HDR handling is not set to 'preserve' ``` **Action:** Update your profile: ```yaml profiles: your_profile: hdr_handling: preserve ``` --- ## Processed File Tracking ### How It Works 1. **First run:** All files scanned and added to database as `pending` 2. **Encoding:** Files marked as `processing` → `completed` or `failed` 3. **Second run:** Completed files automatically skipped 4. **Re-processing:** Reset state to `pending` if needed ### Database Schema ```sql CREATE TABLE files ( id INTEGER PRIMARY KEY, filepath TEXT UNIQUE NOT NULL, state TEXT NOT NULL, -- pending/processing/completed/failed/skipped profile_name TEXT, encoder_used TEXT, encode_time_seconds REAL, fps REAL, original_size INTEGER, encoded_size INTEGER, source_quality_score REAL, -- NEW target_quality_score REAL, -- NEW created_at TIMESTAMP, updated_at TIMESTAMP ); ``` ### Manually Reset Files ```bash # Reset specific file python3 dbmanage.py --reset-file /movies/example.mkv # Reset all files python3 dbmanage.py --reset-all # Reset only failed files python3 dbmanage.py --reset-failed ``` --- ## Command-Line Options ### Check Quality Only (No Encoding) ```bash # Analyze single file python3 quality_checker.py /movies/example.mkv # Batch analyze directory python3 example_quality_check.py /movies/ ``` ### Override Quality Check ```bash # Disable quality check for this run python3 reencode.py -c config.yaml --no-quality-check # Force encode despite warnings python3 reencode.py -c config.yaml --force ``` ### Skip Processed Files ```bash # Skip already completed files (default behavior) python3 reencode.py -c config.yaml # Re-process all files (ignore database) python3 reencode.py -c config.yaml --reprocess-all ``` --- ## Best Practices ### 1. **Start with Quality Analysis** Before encoding your entire library: ```bash # Analyze quality distribution python3 example_quality_check.py /movies/ > quality_report.txt ``` Review the report to understand your source quality distribution. --- ### 2. **Use Appropriate Thresholds** **Conservative (Preserve Quality):** ```yaml quality_check: warn_threshold: 5.0 # Warn on small drops error_threshold: 10.0 # Error on moderate drops skip_on_degradation: true ``` **Balanced (Recommended):** ```yaml quality_check: warn_threshold: 10.0 error_threshold: 20.0 skip_on_degradation: false ``` **Aggressive (Maximum Compression):** ```yaml quality_check: warn_threshold: 20.0 error_threshold: 30.0 skip_on_degradation: false ``` --- ### 3. **Quality-Based Profiles** Use resolution rules to apply different profiles based on source quality: ```yaml advanced: resolution_rules: enabled: true quality_rules: - min_quality: 90 # Near-lossless sources profile: quality_gpu # Use high-quality preset - min_quality: 70 profile: sweetspot_gpu # Balanced - min_quality: 50 profile: balanced_gpu # Already compressed - min_quality: 0 profile: fast_gpu # Low quality sources ``` --- ### 4. **Monitor Processing Logs** Quality checks are logged: ``` 2025-01-15 10:30:22 - INFO - Analyzing quality: example.mkv 2025-01-15 10:30:23 - INFO - Source quality: 72.3/100 2025-01-15 10:30:23 - INFO - Target quality: 75.1/100 2025-01-15 10:30:23 - INFO - ✅ Quality check passed ``` Review logs to identify patterns and adjust settings. --- ## Troubleshooting ### Quality Check Fails **Problem:** `Failed to analyze source video quality` **Solutions:** 1. Check ffprobe is installed: `ffprobe -version` 2. Verify file is readable: `ls -la /path/to/file.mkv` 3. Check file is valid video: `ffprobe /path/to/file.mkv` 4. Disable quality check temporarily: ```yaml quality_check: enabled: false ``` --- ### Inaccurate Quality Scores **Problem:** Quality scores don't match expectations **Explanation:** - Quality scores are **estimates** based on bitrate per pixel - Different content has different complexity - Simple animation: Lower bitrate, high quality - Grain-heavy film: Higher bitrate needed - Scores are relative, not absolute **Solution:** Use thresholds as guidelines, not absolute rules. --- ### Too Many Warnings **Problem:** Getting warnings on files you want to encode **Solutions:** 1. **Increase thresholds:** ```yaml quality_check: warn_threshold: 15.0 # From 10.0 ``` 2. **Disable warnings:** ```yaml quality_check: prompt_on_warning: false ``` 3. **Disable quality check:** ```yaml quality_check: enabled: false ``` --- ## API Reference See `quality_checker.py` for full API documentation. ### QualityChecker Class ```python class QualityChecker: def analyze_quality(self, filepath: Path) -> Optional[VideoQuality]: """Analyze video quality metrics""" def will_degrade_quality( self, source_quality: VideoQuality, target_bitrate: int, target_codec: str, threshold: float = 10.0 ) -> Tuple[bool, str]: """Check if encoding will significantly degrade quality""" def check_before_encode( self, filepath: Path, profile: Dict, warn_threshold: float = 10.0, error_threshold: float = 20.0 ) -> Dict: """Comprehensive quality check before encoding""" def estimate_target_bitrate( self, profile: Dict, resolution: Tuple[int, int], fps: float ) -> int: """Estimate target bitrate based on profile settings""" ``` --- ## Summary The quality checking feature provides: ✅ **Intelligent quality analysis** - Understand your source material ✅ **Degradation detection** - Avoid accidental quality loss ✅ **Processed file tracking** - Skip already-encoded files ✅ **Configurable behavior** - Customize to your needs ✅ **HDR detection** - Preserve HDR metadata ✅ **Detailed logging** - Monitor quality decisions **Best Use Cases:** - Large mixed-quality libraries - Preserving high-quality sources - Avoiding re-encoding already compressed files - Understanding quality impact before encoding **When to Disable:** - All sources are known low quality - Testing encoding settings - Processing screen recordings - Time-sensitive batch jobs