conversion_project/README.md
2026-05-17 21:21:28 -04:00

1062 lines
32 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# AV1 Batch Video Transcoder
A high-performance batch video transcoding tool using NVIDIA's **AV1 NVENC** or **HEVC NVENC** codec with intelligent audio/subtitle handling, interactive stream selection, and automatic quality optimization.
---
## 📋 Table of Contents
1. [Key Features](#-key-features)
2. [Quick Start](#-quick-start)
3. [Installation](#installation)
4. [Basic Usage](#basic-usage)
5. [Command Reference](#command-reference)
6. [Batch Processing](#batch-processing)
7. [Audio Options](#audio-options)
8. [Undefined Language Replacement](#undefined-language-und-replacement)
9. [Encoder Selection](#encoder-selection)
10. [Configuration](#configuration)
11. [Project Structure](#project-structure)
12. [Encoding Process](#encoding-process)
13. [Troubleshooting](#troubleshooting)
---
## ✨ Key Features
### Video Encoding
- **Dual Encoder Support** - NVIDIA AV1 NVENC (8-bit, default) or HEVC NVENC (10-bit)
- **Smart Resolution** - Detects source resolution, scales 4K→1080p, preserves lower resolutions
- **GPU Acceleration** - Hardware encoding via NVIDIA NVENC (RTX 2060+)
- **Two-Phase Mode** - CQ mode first, automatic Bitrate fallback if size threshold exceeded
- **Quality Presets** - Per-content-type CQ values (TV/Movies, 720p/1080p)
### Audio Processing
- **Smart Audio Processing** - Auto-detects bitrate, AAC for stereo, EAC3 for 5.1
- **Stream Selection** - Keep only best English + Commentary (automatic) or choose manually (interactive)
- **Interactive Selection** - View all audio streams and select which ones to keep per file
- **Channel Control** - Force specific channel counts (2-channel stereo or 6-channel 5.1 surround)
- **Audio Titles** - Rename/tag audio streams with custom titles
- **Language Tagging** - Optional language code metadata for audio streams
### Subtitles & Metadata
- **Subtitle Embedding** - Auto-detects and embeds subtitles (.vtt, .srt, .ass, .ssa, .sub)
- **Language-Prefixed Subtitles** - Finds language-specific files (movie.en.vtt, movie.eng.vtt)
- **Automatic Cleanup** - Deletes subtitle files after embedding
### Processing Features
- **CSV Tracking** - Detailed conversion logs with compression ratios and media context
- **Automatic Cleanup** - Deletes originals + subtitles after successful encoding
- **Test Mode** - Encode one file, check compression ratio before batch processing
- **Structured Logging** - JSON logs with media type, show name, season/episode context
- **File Tagging** - Output files get ` - [EHX]` suffix for easy identification
---
## 🚀 Quick Start
### Requirements
- **Python 3.8+**
- **FFmpeg** with libfdk-aac support
- **NVIDIA GPU** (GeForce RTX 2060+, Quadro, or newer)
- **NVIDIA CUDA Toolkit** (for NVENC support)
### Installation
```bash
# Clone repository
git clone https://github.com/yourusername/conversion_project.git
cd conversion_project
# Install Python dependencies (if any needed in future)
# pip install -r requirements.txt
```
### Basic Usage
```bash
# Encode a TV folder (smart mode with AV1, default)
python main.py "P:\tv\Show Name"
# Use HEVC encoder (10-bit, better Plex compatibility)
python main.py "P:\tv\Show Name" --encoder nvenc
# Test single file before batch processing
python main.py "P:\tv\Show Name" --test
# Force specific quality (CQ 30)
python main.py "P:\movies\Movie" --cq 30
# Force bitrate mode
python main.py "P:\tv\Show" --m bitrate
# Specific resolution
python main.py "P:\movies" --r 720
# Tag audio with language
python main.py "P:\tv\Show" --language eng
# Interactive audio selection
python main.py "P:\tv\Show" --filter-audio --interactive
```
---
## Command Reference
### Encoder Selection
```bash
--encoder {av1,nvenc}
```
- `av1` (default): AV1 NVENC, 8-bit, smaller files (~baseline compression)
- `nvenc`: HEVC NVENC, 10-bit, larger files (~80-90% of AV1), better compatibility
### Quality & Mode
```bash
--cq <value> # Use CQ mode with specific quality (0-51, lower=better)
--m {cq,bitrate} # Force encoding mode (default: smart two-phase)
```
### Resolution
```bash
--r {480,720,1080} # Force specific output resolution
# Default: scale 4K→1080p, preserve lower
```
### Audio Options
```bash
--filter-audio # Enable automatic audio filtering (keep English + Commentary)
--interactive # Interactive mode: show audio streams, user selects which to keep
--audio-select "0,1" # Pre-select specific audio streams (indices)
--audio-titles "0:English,1:Commentary" # Rename/title audio tracks
--audio-channels "0:2,1:6" # Force channel count (2=stereo, 6=5.1 surround)
--language eng # Tag audio streams with language code
--default-language spa # Set default language for undefined (und) audio tracks
--no-replace-und # Disable undefined language tag replacement
```
### Undefined Language (und) Replacement
Automatically replaces undefined (`und`) audio language tags with a configurable default language. Most useful when your video library has audio with undefined language tags that should actually be marked as a specific language.
#### Configuration
Add to `config.xml` in the `<general>` section:
```xml
<!-- Default language for undefined (und) audio tracks -->
<!-- Set to desired ISO 639-2 code (eng, spa, fra, deu, etc.) or 'und' to disable -->
<default_language>eng</default_language>
<!-- Replace undefined language tracks with default language -->
<replace_undefined_language>true</replace_undefined_language>
```
#### CLI Arguments
**`--default-language <LANG>`** - Override the default language for a single run:
```bash
python main.py "P:\movies\Collection" --default-language spa
python main.py "P:\tv\Show" --default-language fra
```
**`--no-replace-und`** - Disable undefined language replacement for a single run:
```bash
python main.py "P:\movies\Collection" --no-replace-und
```
#### Behavior
**Priority Chain** (highest to lowest):
1. `--language eng` (CLI): Tags ALL audio streams as 'eng'
2. `--default-language spa` + detected `und`: Replaces with 'spa'
3. config.xml `default_language: eng` + detected `und`: Replaces with 'eng'
4. `--no-replace-und` flag: Skips all `und` replacement
**Key Points:**
- Only affects 'und' language tags (existing language tags are preserved)
- Works with batch processing (`--paths-file`)
- Compatible with TV/movie/anime detection
- Works in CQ mode, Bitrate mode, and Smart mode
#### Common Language Codes
| Code | Language | Code | Language |
|------|----------|------|----------|
| eng | English | jpn | Japanese |
| spa | Spanish | kor | Korean |
| fra | French | zho | Chinese (Mandarin) |
| deu | German | rus | Russian |
| ita | Italian | por | Portuguese |
Full list: https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes
#### Examples
**Example 1: Most content is English with `und` tags**
```bash
# config.xml already has: <default_language>eng</default_language>
python main.py "P:\movies"
# Result: All 'und' audio streams are tagged as 'eng'
```
**Example 2: Mixed language batch with different defaults**
```
# paths.txt
"P:\movies\English Collection" --default-language eng
"P:\movies\Spanish Collection" --default-language spa
"P:\movies\Mixed" --no-replace-und
```
```bash
python main.py --paths-file paths.txt
```
### Processing
```bash
--test # Test mode: encode first file, show compression ratio, don't move
```
---
## Batch Processing
### Overview
Process multiple folders sequentially with different parameters for each. Perfect for encoding your entire media library with specific settings per movie/show.
### Quick Start
```bash
# Simple list format (paths.txt)
python main.py --paths-file paths.txt
# CSV format with custom parameters (paths_batch.csv)
python main.py --paths-file paths_batch.csv
```
### File Formats
#### Format 1: Simple List (paths.txt)
One path per line, with optional per-row parameters:
```
P:\movies\Nobody 2 (2025)
P:\movies\The French Dispatch (2021) --r 720
P:\movies\Let's Be Cops (2014) --r 720 --cq 28
P:\movies\Akira (1988) --encoder av1 --strip-all-titles
## Batch Processing
### Overview
Process multiple folders sequentially with different parameters for each. This replaces the need for manual `.bat` files or shell scripts. Perfect for encoding your entire media library with specific settings per movie/show.
### Quick Start
#### Simple List Format (paths.txt)
One path per line, with optional per-row parameters:
```
P:\movies\Nobody 2 (2025)
P:\movies\The French Dispatch (2021) --r 720
P:\movies\Let's Be Cops (2014) --r 720 --cq 28
P:\movies\Akira (1988) --encoder av1 --strip-all-titles
```
**Usage:**
```bash
python main.py --paths-file paths.txt
```
**With base parameters** (applied to all rows unless overridden):
```bash
python main.py --paths-file paths.txt --encoder hevc --strip-all-titles
```
#### CSV Format (paths_batch.csv)
First column is path, remaining columns are optional parameters:
```csv
path,resolution,cq,encoder,notes
"P:\movies\Nobody 2 (2025)","--r 1080","--cq 32","--encoder hevc","4K source"
"P:\movies\The French Dispatch (2021)","--r 720","--cq 28","--encoder av1","720p source"
"P:\movies\Let's Be Cops (2014)","--r 720"
"P:\movies\Akira (1988)","","--cq 26"
```
**Usage:**
```bash
python main.py --paths-file paths_batch.csv
```
The CSV header row is ignored - use it for your own documentation.
### Supported List Formats
#### Simple List (One per line)
```
# Path only (uses base parameters)
P:\movies\Movie1
# Path with space-separated parameters
P:\movies\Movie2 --r 720
P:\movies\Movie3 --r 720 --cq 28 --encoder av1
# Quoted paths with spaces
"P:\movies\Movie with Spaces" --r 720
# Comment out paths with #
# P:\movies\Disabled --r 480
```
#### CSV Format (Recommended for complex setups)
First column is always the path. Remaining columns can be any parameters:
```csv
path,resolution,quality,encoder,language
"P:\movies\Movie1","--r 1080","--cq 32","--encoder hevc","--language eng"
"P:\movies\Movie2","--r 720","--cq 28","--encoder av1"
"P:\movies\Movie3","--r 720"
```
### Per-Row Parameter Override
Row parameters **override** base CLI parameters for that specific path.
**Example:**
```bash
# Base command with --strip-all-titles applied to all
python main.py --paths-file paths.txt --strip-all-titles
```
With `paths.txt`:
```
P:\movies\Movie1 # Uses --strip-all-titles from base
P:\movies\Movie2 --keep-all-titles # OVERRIDES to keep titles, still strips
P:\movies\Movie3 --encoder av1 # OVERRIDES encoder to av1
P:\movies\Movie4 --r 720 --cq 28 # OVERRIDES resolution and quality
```
### All Supported Per-Row Parameters
Any CLI parameter can be used in rows:
```
--r {480,720,1080} # Resolution
--cq <value> # CQ quality (0-51, lower is better)
--m {cq,bitrate} # Encoding mode
--encoder {av1,hevc} # Video encoder
--audio-channels "0:2,1:6" # Force audio channels
--audio-titles "0:English,1:Commentary" # Audio track names
--audio-select "0,1" # Pre-select audio streams
--language eng # Language tag
--filter-audio # Enable audio filtering
--strip-all-titles # Remove audio titles
--keep-all-titles # Preserve audio titles
--unforce-subs # Remove forced subtitle flag
--no-encode # Mux only, no encoding
--test # Test mode (first file only)
--crop-height <pixels> # Crop to height
--color-bit {8,10} # Color bit depth (HEVC only)
```
### Real-World Examples
**Example 1: Movie Library with Varying Quality**
`movies.txt`:
```
P:\movies\4K Movies\Movie1 --r 1080 --cq 26
P:\movies\4K Movies\Movie2 --r 1080 --cq 26
P:\movies\720p Movies\Movie3 --r 720 --cq 28
P:\movies\Anime\Anime1 --encoder av1 --cq 26
P:\movies\Anime\Anime2 --encoder av1 --cq 26 --audio-channels "0:2"
```
```bash
python main.py --paths-file movies.txt --encoder hevc --strip-all-titles
```
**Example 2: TV Shows by Season**
`tv.csv`:
```csv
path,params
"P:\tv\Breaking Bad\Season 1","--cq 26"
"P:\tv\Breaking Bad\Season 2","--cq 28"
"P:\tv\Breaking Bad\Season 3","--cq 28 --r 720"
"P:\tv\Game of Thrones\Season 1","--encoder hevc --cq 24"
"P:\tv\Game of Thrones\Season 2","--encoder hevc --cq 26"
```
```bash
python main.py --paths-file tv.csv --filter-audio
```
**Example 3: Mixed Content with Language Tags**
`archive.txt`:
```
# Movies
P:\content\Movies\Action\MovieA --r 1080 --cq 28 --encoder hevc
P:\content\Movies\Drama\MovieB --r 1080 --cq 26 --encoder hevc
# TV Shows
P:\content\TV\Show1\Season1 --cq 28 --filter-audio
P:\content\TV\Show2\Season1 --cq 26 --filter-audio --language eng
# Anime
P:\content\Anime\SeriesA --encoder av1 --cq 24
P:\content\Anime\SeriesB --encoder av1 --cq 26 --audio-channels "0:2"
```
```bash
python main.py --paths-file archive.txt --strip-all-titles
```
### Batch Processing Output
During execution, you'll see detailed progress:
```
════════════════════════════════════════════════════════════════════════════════
BATCH MODE: Processing paths from paths.txt
════════════════════════════════════════════════════════════════════════════════
────────────────────────────────────────────────────────────────────────────────
BATCH [1/5]: P:\movies\Movie1
────────────────────────────────────────────────────────────────────────────────
[... encoding output ...]
✓ [BATCH 1/5] Completed: Movie1
────────────────────────────────────────────────────────────────────────────────
BATCH [2/5]: P:\movies\Movie2
Parameters: --r 720
────────────────────────────────────────────────────────────────────────────────
[... encoding output ...]
✓ [BATCH 2/5] Completed: Movie2
[... continues ...]
════════════════════════════════════════════════════════════════════════════════
✓ BATCH PROCESSING COMPLETE: Processed 5 path(s)
════════════════════════════════════════════════════════════════════════════════
```
**Key features:**
- Each path prefixed with `[BATCH X/Y]` in logs
- If a path fails, processing continues to next path
- Overall summary shows completion status
### Batch Processing Tips & Best Practices
#### 1. Test Before Full Batch
Use `--test` flag per-row to verify settings:
```
P:\movies\TestMovie --test --r 720 --cq 28
P:\movies\Movie1 --r 720 --cq 28
P:\movies\Movie2 --r 720 --cq 28
```
#### 2. Start Simple, Add Complexity
```bash
# Phase 1: Just paths
python main.py --paths-file paths.txt
# Phase 2: Add base parameters
python main.py --paths-file paths.txt --encoder hevc
# Phase 3: Add per-row customization in the file
```
#### 3. Monitor Progress
Check logs in `logs/conversion.log` during batch processing:
- Each entry includes `[BATCH X/Y]` prefix
- All parameters are logged per file
- Search for errors with the batch prefix
#### 4. CSV Format Tips
- Quote paths with spaces: `"P:\path with spaces"`
- Leave empty cells for defaults: `"P:\movies\Movie1","--r 720"` (uses default CQ)
- Or combine in one cell: `"P:\movies\Movie1","--r 720 --cq 28"`
#### 5. Line Endings
- Both Unix (LF) and Windows (CRLF) line endings work
- Avoid mixing line endings in the same file
#### 6. Encoding Issues
If you get encoding errors:
- Ensure file is saved as UTF-8
- Use English characters in parameter values
- Avoid special characters in paths
### Migration from .bat Files
**Old .bat approach:**
```batch
python main.py "P:\movies\Movie1"
python main.py "P:\movies\Movie2" --r 720
python main.py "P:\movies\Movie3" --r 720 --cq 28
```
**New --paths-file approach:**
```bash
python main.py --paths-file paths.txt
```
With `paths.txt`:
```
P:\movies\Movie1
P:\movies\Movie2 --r 720
P:\movies\Movie3 --r 720 --cq 28
```
**Benefits:**
- Single command to start batch
- All parameters visible in one file
- Easier to edit and maintain
- Better error handling (continues on failure)
- Unified logging with batch context
---
## Audio Options
### Three Main Audio Control Methods
| Option | Purpose | Format | Example |
|--------|---------|--------|---------|
| `--audio-select` | Pre-select which streams to keep | Comma-separated indices | `--audio-select "0,1,2"` |
| `--audio-titles` | Rename/title tracks | `index:title` pairs | `--audio-titles "0:English,1:Commentary"` |
| `--audio-channels` | Set channel count per track | `index:channels` pairs | `--audio-channels "0:2,1:6"` |
### Audio Filtering
**Automatic Filtering** (`--filter-audio`):
```bash
python main.py "C:\Videos" --filter-audio
```
- Automatically keeps best English audio + all Commentary tracks
- Removes other languages
- No user interaction
**Interactive Filtering** (`--filter-audio --interactive`):
```bash
python main.py "C:\Videos" --filter-audio --interactive
```
- Shows all audio streams for each file
- User selects which streams to keep
- Different selections allowed per file
**Stream Display Format**:
```
🎵 AUDIO STREAM SELECTION
================================================================================
Stream #0: 2ch | Lang: eng | Bitrate: 128kbps
Stream #1: 6ch | Lang: eng | Bitrate: 448kbps
Stream #2: 2ch | Lang: spa | Bitrate: 128kbps
────────────────────────────────────────────────────────────────────────────
Enter stream numbers to keep (comma-separated, e.g.: 1,2 or just 2)
Leave blank to keep all streams
────────────────────────────────────────────────────────────────────────────
➜ Keep streams: 1,3
```
### Audio Channel Control
**--audio-channels** allows forcing specific channel configurations:
```bash
# Force stereo for all tracks
python main.py "C:\Videos" --audio-channels "0:2,1:2"
# Keep 5.1 main audio, compress commentary to stereo
python main.py "C:\Videos" --audio-channels "0:6,1:2" --audio-titles "0:English 5.1,1:Commentary"
```
**Valid Channels**: 2 (stereo) or 6 (5.1 surround)
**Automatic Bitrate Selection**:
| Resolution | Stereo (2ch) | 5.1 Surround (6ch) |
|-----------|------------|-----------------|
| 1080p | 192 kbps | 384 kbps |
| 720p | 160 kbps | 320 kbps |
### Audio Filtering Priority
When determining output channels for a stream:
1. **User-specified via `--audio-channels`** (highest priority)
2. **Commentary detection** (if titled "Commentary", forces 2-channel)
3. **Auto-detection** (default, based on resolution and source channels)
### Common Audio Scenarios
**Scenario 1: TV Show with Commentary**
```bash
python main.py "C:\TV" \
--audio-channels "0:2,1:2" \
--audio-titles "0:English,1:Commentary"
```
**Scenario 2: Movie Collection (Multiple Languages)**
```bash
python main.py "C:\Movies" \
--audio-select "0,1,2" \
--audio-channels "0:6,1:2,2:2" \
--audio-titles "0:Japanese 5.1,1:English Stereo,2:Spanish Stereo"
```
**Scenario 3: Anime (All Stereo)**
```bash
python main.py "C:\Anime" --audio-channels "0:2,1:2,2:2"
```
---
## Encoder Selection
### Dual Encoder Support
**AV1 NVENC (Default)**
```bash
python main.py "C:\Videos" --encoder av1
```
- **Codec**: av1_nvenc
- **Preset**: p7 (high quality)
- **Bit Depth**: 8-bit
- **Pixel Format**: yuv420p
- **File Size**: Smallest (~baseline)
- **Use Case**: Maximum file size reduction, modern playback devices
**HEVC NVENC**
```bash
python main.py "C:\Videos" --encoder nvenc
```
- **Codec**: hevc_nvenc
- **Preset**: slow (high quality)
- **Bit Depth**: 10-bit
- **Pixel Format**: yuv420p10le
- **File Size**: ~80-90% of AV1 size
- **Use Case**: Best quality archival, excellent Plex compatibility
### Quality Comparison
| Aspect | HEVC NVENC | AV1 NVENC |
|--------|-----------|----------|
| **File Size** | ~80-90% of AV1 | Smallest (baseline) |
| **Quality** | Excellent | Excellent |
| **Preset** | slow (p6) | p7 |
| **Bit Depth** | 10-bit | 8-bit |
| **Compatibility** | Excellent (Plex) | Good (modern devices) |
| **Encoding Speed** | Fast | Fast |
---
## ⚙️ Configuration
Edit `config.xml` to customize encoding parameters:
### Video Encoder Settings
```xml
<encoder default="av1">
<av1_nvenc preset="p7" bit_depth="8" pix_fmt="yuv420p" />
<hevc_nvenc preset="slow" bit_depth="10" pix_fmt="yuv420p10le" />
</encoder>
```
### CQ Quality Per Content Type
```xml
<cq>
<tv_1080>28</tv_1080>
<tv_720>32</tv_720>
<movie_1080>32</movie_1080>
<movie_720>34</movie_720>
</cq>
```
### Audio Bitrate Buckets
```xml
<audio>
<stereo>
<high>192000</high>
<medium>160000</medium>
</stereo>
<multi_channel>
<medium>448000</medium>
<low>384000</low>
</multi_channel>
</audio>
```
### Bitrate Fallback (Phase 2)
```xml
<fallback>
<bitrate_1080>8000</bitrate_1080>
<bitrate_720>6000</bitrate_720>
<bitrate_480>4000</bitrate_480>
</fallback>
```
### Subtitle Detection
```xml
<subtitles>
<enabled>true</enabled>
<extensions>.vtt,.srt,.ass,.ssa,.sub</extensions>
<codec>subrip</codec> <!-- subrip for .srt format -->
</subtitles>
```
### General Settings
```xml
<general>
<processing_folder>.\processing</processing_folder>
<suffix> - [EHX]</suffix>
<video_extensions>.mkv,.mp4,.avi,.m2ts</video_extensions>
<reduction_ratio_threshold>0.75</reduction_ratio_threshold>
</general>
```
---
## Project Structure
```
conversion_project/
├── main.py - CLI entry point for batch transcoding
├── config.xml - Configuration (encoding settings, audio buckets, etc.)
├── core/ - Core modules
│ ├── config_helper.py - XML configuration loader
│ ├── logger_helper.py - Logging setup (JSON structured logs)
│ ├── process_manager.py - Main transcoding orchestration
│ ├── encode_engine.py - FFmpeg command builder and execution
│ ├── audio_handler.py - Audio stream analysis, bitrate decisions, interactive selection
│ ├── video_handler.py - Video resolution detection and scaling logic
│ └── hardware_helper.py - Hardware detection (GPU/CPU)
├── /rename/ - Separate rename utility (rolling_rename.py)
├── /path_manager/ - GUI path management
│ ├── gui_path_manager.py
│ ├── transcode.bat
│ ├── paths.txt
│ └── cache/
├── logs/ - Log files and conversion tracker CSV
├── processing/ - Temporary encoding files (cleaned up after move)
└── README.md - This file
```
---
## Encoding Process
### Per-File Workflow
For each video file in the target folder:
1. **Detect Subtitles**
- Looks for exact match: `Video.vtt`, `Video.srt`, etc.
- Also searches for language-prefixed: `Video.en.vtt`, `Video.eng.vtt`
2. **Analyze Source**
- Detect resolution (width × height)
- Extract audio streams (codec, channels, bitrate, language)
- Extract video codec and frame rate
3. **Determine Parameters**
- **Target Resolution**: Scale 4K→1080p, preserve lower resolutions (or use `--r` override)
- **CQ Value**: Select based on content type and resolution (tv_1080, movie_720, etc.)
- **Audio Processing**:
- Apply filtering/selection if specified
- Choose codec (AAC for stereo, EAC3 for 5.1)
- Choose bitrate (depends on resolution and stream quality)
4. **FFmpeg Encode**
- **Video**: AV1 NVENC 8-bit yuv420p (or HEVC NVENC 10-bit)
- **Audio**: Per-stream decisions (copy if good quality, re-encode if excessive bitrate)
- **Subtitles**: Embed as SRT (if found)
5. **Size Validation**
- Compare output size vs original size
- If output > 75% of original (default threshold), retry with Phase 2 (bitrate mode)
6. **Move File**
- Move from temp folder → original location
- Add ` - [EHX]` suffix to filename
- Delete original file and subtitle file
7. **Logging**
- Record to CSV tracker: filename, original size, output size, compression ratio
- Structured JSON logging with media context (show name, season, episode)
### Audio Encoding Logic
```
For each audio stream:
Stereo audio (2 channels)?
├─ YES + 1080p:
│ ├─ If >192kbps → ENCODE to 192 kbps AAC
│ └─ If ≤192kbps → COPY (no re-encoding)
├─ YES + 720p:
│ ├─ If >160kbps → ENCODE to 160 kbps AAC
│ └─ If ≤160kbps → COPY (no re-encoding)
└─ NO (Multichannel/5.1+):
├─ ENCODE to 384 kbps or 448 kbps EAC3 (depending on resolution)
```
---
## 📊 Example Output
**Input File:**
```
SupernaturalS07E21.mkv (size: 1.5GB, 6-channel AC3 384kbps, 1920x1080)
SupernaturalS07E21.en.vtt (subtitle)
```
**Processing:**
```
Detected: 1920x1080 (1080p) → TV episode CQ 28
Audio: 6ch AC3 384kbps (needs re-encoding for 5.1)
Subtitle: Detected SupernaturalS07E21.en.vtt
```
**Output File:**
```
SupernaturalS07E21 - [EHX].mkv (size: 420MB, EAC3 384kbps, subtitle embedded)
Compression: 1500MB → 420MB (72% reduction)
```
---
## Troubleshooting
### Common Issues
**"FFmpeg not found"**
- Ensure FFmpeg is installed and in your system PATH
- Test with: `ffmpeg -version`
**"GPU out of memory"**
- NVIDIA GPU is full, close other GPU applications
- Or reduce resolution with `--r 720`
**"Subtitle not embedding"**
- Ensure subtitle file is in same folder as video
- Check subtitle extension is in config.xml (vtt, srt, ass, etc.)
- Verify filename matches exactly (e.g., `Video.en.vtt`)
**"No audio streams detected"**
- Run `ffprobe input.mkv` to verify audio streams exist
- Audio may be embedded as data track, not audio track
**"CUDA Kernel Error" during encoding**
- GPU driver is outdated, update NVIDIA drivers
- GPU may be overheating, check temperature
**"Output file larger than original"**
- Phase 1 (CQ mode) exceeded size threshold
- Phase 2 (bitrate mode) will retry automatically
- Or manually increase CQ value (lower quality) in config.xml
---
## Advanced Features
### Test Mode
Encodes first file only without moving it:
```bash
python main.py "P:\tv\Show" --test
```
**Use Case**: Test CQ values, check quality before batch processing entire library.
### Language Tagging
Tags audio streams with language metadata (only if specified):
```bash
python main.py "P:\tv\Show" --language eng
```
Without the flag, original audio metadata is preserved.
### Resolution Override
Force specific output resolution regardless of source:
```bash
python main.py "P:\movies" --r 720 # Force 720p
python main.py "P:\tv" --r 1080 # Force 1080p
```
### CSV Conversion Tracking
All conversions logged to CSV file with:
- Filename
- Original size
- Output size
- Compression ratio
- Encoding method (CQ/Bitrate)
- Duration
- Timestamp
---
## Logging
The system uses structured JSON logging with media context:
### Log Fields
- **timestamp**: When the conversion occurred
- **level**: INFO, WARNING, ERROR
- **message**: Human-readable conversion status
- **video_filename**: Original filename
- **media_type**: "tv", "anime", "movie", or "other"
- **show_name**: Extracted from path (e.g., "Breaking Bad")
- **season**: TV/anime season number (optional)
- **episode**: TV/anime episode number (optional)
- **method**: "CQ" or "Bitrate"
- **original_size_mb**: Input file size
- **output_size_mb**: Output file size
- **reduction_pct**: Compression percentage
### Log Files
- **logs/conversion.log**: Full structured JSON logs (INFO level and above)
- **logs/conversion_failures.log**: Error and failure logs only
- **conversion_tracker.csv**: Human-readable conversion summary
---
## Recent Changes
### Latest Updates
**Dual Encoder Support** - Switch between AV1 and HEVC with `--encoder` flag
**Interactive Audio Selection** - Manually choose which audio streams to keep
**Audio Channel Control** - Force specific channel counts (2-ch stereo or 6-ch 5.1)
**Audio Stream Titles** - Rename/tag individual audio tracks
**Structured JSON Logging** - Media context in all logs (show name, season, episode)
**Subtitle Embedding** - Auto-detect and embed subtitles with language prefixes
**Test Mode** - Encode first file to verify settings before batch processing
### Removed Features
❌ Sonarr/Radarr integration (simplified for reliability)
❌ Auto-rename based on external metadata
❌ Web UI (can be added back if needed)
---
## 📊 Example Output
**Input:**
```
Show.S01E01.mkv (1.5GB)
Show.S01E01.en.vtt (subtitle)
```
**Output:**
```
Show.S01E01 - [EHX].mkv (450MB, subtitle embedded, audio tagged)
```
**Compression:** 1.5GB → 450MB (30% ratio, 70% reduction)
## 🔧 Encoding Specs
| Setting | Value |
|---------|-------|
| Video Codec | AV1 (av1_nvenc) |
| Bit Depth | 8-bit (yuv420p) |
| GPU Preset | p1 (high quality) |
| Audio Codec | AAC |
| Audio Mode | Smart (copy or re-encode) |
| Container | MKV |
| Subtitles | Embedded SRT |
## 🎯 Workflow
1. **Scan** folder for video files
2. **Detect** subtitles, audio streams, resolution
3. **Encode** with AV1 codec (Phase 1: CQ)
4. **Check** size threshold (default 75%)
5. **Retry** with Bitrate mode if needed (Phase 2)
6. **Move** encoded file to original location
7. **Cleanup** original + subtitles + temp files
8. **Log** results to CSV tracker
## 📋 Requirements
- Windows 10/11 or Linux
- NVIDIA GPU with NVENC support
- NVIDIA CUDA Toolkit 11.0+
- FFmpeg compiled with av1_nvenc support
- Python 3.8+
## 🛠️ Troubleshooting
**Files not moving?**
- Check `reduction_ratio_threshold` in config.xml (default 0.75)
- Run with `--test` to see compression ratio
**Subtitles not embedding?**
- Verify filename: `video.en.vtt` or `video.vtt`
- Check config.xml `<subtitles><enabled>true</enabled>`
**Wrong audio quality?**
- Adjust CQ values in config.xml per content type
- Use `--cq` override: `python main.py folder --cq 30`
**"FFmpeg not found"**
- Ensure FFmpeg is installed and in your system PATH
- Test with: `ffmpeg -version`
**"GPU out of memory"**
- NVIDIA GPU is full, close other GPU applications
- Or reduce resolution with `--r 720`
**"No audio streams detected"**
- Run `ffprobe input.mkv` to verify audio streams exist
- Audio may be embedded as data track, not audio track
**"CUDA Kernel Error" during encoding**
- GPU driver is outdated, update NVIDIA drivers
- GPU may be overheating, check temperature
**"Output file larger than original"**
- Phase 1 (CQ mode) exceeded size threshold
- Phase 2 (bitrate mode) will retry automatically
- Or manually increase CQ value (lower quality) in config.xml
## 📄 License
MIT