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

32 KiB
Raw Blame History

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
  2. Quick Start
  3. Installation
  4. Basic Usage
  5. Command Reference
  6. Batch Processing
  7. Audio Options
  8. Undefined Language Replacement
  9. Encoder Selection
  10. Configuration
  11. Project Structure
  12. Encoding Process
  13. 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

# 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

# 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

--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

--cq <value>           # Use CQ mode with specific quality (0-51, lower=better)
--m {cq,bitrate}       # Force encoding mode (default: smart two-phase)

Resolution

--r {480,720,1080}     # Force specific output resolution
                       # Default: scale 4K→1080p, preserve lower

Audio Options

--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:

<!-- 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:

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:

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

# 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
python main.py --paths-file paths.txt

Processing

--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

# 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):

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:

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:

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

First column is always the path. Remaining columns can be any parameters:

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:

# 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"
python main.py --paths-file movies.txt --encoder hevc --strip-all-titles

Example 2: TV Shows by Season

tv.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"
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"
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

# 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:

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:

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):

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):

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:

# 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

python main.py "C:\TV" \
  --audio-channels "0:2,1:2" \
  --audio-titles "0:English,1:Commentary"

Scenario 2: Movie Collection (Multiple Languages)

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)

python main.py "C:\Anime" --audio-channels "0:2,1:2,2:2"

Encoder Selection

Dual Encoder Support

AV1 NVENC (Default)

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

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

<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

<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

<audio>
  <stereo>
    <high>192000</high>
    <medium>160000</medium>
  </stereo>
  <multi_channel>
    <medium>448000</medium>
    <low>384000</low>
  </multi_channel>
</audio>

Bitrate Fallback (Phase 2)

<fallback>
  <bitrate_1080>8000</bitrate_1080>
  <bitrate_720>6000</bitrate_720>
  <bitrate_480>4000</bitrate_480>
</fallback>

Subtitle Detection

<subtitles>
  <enabled>true</enabled>
  <extensions>.vtt,.srt,.ass,.ssa,.sub</extensions>
  <codec>subrip</codec>  <!-- subrip for .srt format -->
</subtitles>

General Settings

<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:

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):

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:

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