Added actualy HW encode
This commit is contained in:
102
SETUP.md
102
SETUP.md
@@ -94,9 +94,12 @@ All wrapper scripts (`run_optimisation.sh` on Linux, `run_optimisation.ps1` on W
|
|||||||
| `--preset <value>` | SVT-AV1 Preset (4=best, 6=balanced, 8=fast) | 6 |
|
| `--preset <value>` | SVT-AV1 Preset (4=best, 6=balanced, 8=fast) | 6 |
|
||||||
| `--workers <count>` | Concurrent files to process | 1 |
|
| `--workers <count>` | Concurrent files to process | 1 |
|
||||||
| `--samples <count>` | Samples for CRF search | 4 |
|
| `--samples <count>` | Samples for CRF search | 4 |
|
||||||
| `--thorough` | Use thorough mode (slower, more accurate) | false |
|
| `--encoder <name>` | Video encoder: svt-av1, av1_amf, av1_nvenc, av1_qsv | svt-av1 |
|
||||||
| `--encoder <name>` | ab-av1 encoder | svt-av1 |
|
| `--hwaccel <value>` | Hardware decode acceleration (auto, d3d11va, vaapi) | none |
|
||||||
| `--hwaccel <value>` | Hardware acceleration | none (auto: auto-detect) |
|
| `--use-hardware-worker` | Use 1 HW encoder worker + rest CPU workers | false |
|
||||||
|
| `--plex-url <url>` | Plex server URL for library refresh | none |
|
||||||
|
| `--plex-token <token>` | Plex auth token | none |
|
||||||
|
| `--log-dir <path>` | Log directory | /opt/Optmiser/logs |
|
||||||
|
|
||||||
## Multi-Machine Setup
|
## Multi-Machine Setup
|
||||||
|
|
||||||
@@ -140,6 +143,99 @@ All three can run simultaneously!
|
|||||||
|
|
||||||
## Hardware Acceleration
|
## Hardware Acceleration
|
||||||
|
|
||||||
|
### Hardware Decoding vs Hardware Encoding
|
||||||
|
|
||||||
|
There are two types of hardware acceleration:
|
||||||
|
|
||||||
|
1. **Hardware Decoding (`--hwaccel`)**: Uses GPU to decode source video faster. Doesn't affect quality.
|
||||||
|
2. **Hardware Encoding (`--encoder`)**: Uses GPU to encode output video. Much faster but requires quality compensation.
|
||||||
|
|
||||||
|
### Hardware Encoders
|
||||||
|
|
||||||
|
| Encoder | GPU | Platform | Notes |
|
||||||
|
|---------|-----|----------|-------|
|
||||||
|
| `svt-av1` | CPU | All | Default. Best quality, slowest. |
|
||||||
|
| `av1_amf` | AMD | Windows/Linux | RX 7000 series, ~3-10x faster than CPU |
|
||||||
|
| `av1_nvenc` | NVIDIA | Windows/Linux | RTX 40 series, very fast |
|
||||||
|
| `av1_qsv` | Intel | Windows/Linux | Arc GPUs, Intel iGPU with AV1 |
|
||||||
|
|
||||||
|
### FFmpeg with Hardware Encoder Support
|
||||||
|
|
||||||
|
**Windows (pre-built with HW encoders):**
|
||||||
|
```powershell
|
||||||
|
# Most Windows FFmpeg builds include hardware encoders
|
||||||
|
# Verify with:
|
||||||
|
ffmpeg -encoders 2>&1 | findstr av1
|
||||||
|
|
||||||
|
# Should show: av1_amf, av1_nvenc, av1_qsv (depending on your GPU)
|
||||||
|
|
||||||
|
# If missing, download from: https://github.com/BtbN/FFmpeg-Builds/releases
|
||||||
|
# Choose: ffmpeg-master-latest-win64-gpl.zip (includes all encoders)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Linux (may need custom build):**
|
||||||
|
```bash
|
||||||
|
# Check available encoders
|
||||||
|
ffmpeg -encoders 2>&1 | grep av1
|
||||||
|
|
||||||
|
# For AMD (av1_amf) - requires AMF SDK
|
||||||
|
# Install AMD GPU drivers with AMF support
|
||||||
|
sudo apt install amdgpu-pro
|
||||||
|
|
||||||
|
# For NVIDIA (av1_nvenc) - requires NVIDIA drivers
|
||||||
|
sudo apt install nvidia-driver-535 # or newer
|
||||||
|
|
||||||
|
# For Intel (av1_qsv) - requires Intel Media SDK
|
||||||
|
sudo apt install intel-media-va-driver-non-free
|
||||||
|
|
||||||
|
# If your distro's ffmpeg lacks HW encoders, use static build:
|
||||||
|
wget https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using Hardware Workers (1 GPU + 3 CPU)
|
||||||
|
|
||||||
|
For mixed encoding with your RX 7900 XT:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Windows - 4 workers: 1 uses GPU (av1_amf), 3 use CPU (svt-av1)
|
||||||
|
.\run_optimisation.ps1 `
|
||||||
|
-Directory "Z:\" `
|
||||||
|
-Vmaf 94 `
|
||||||
|
-Workers 4 `
|
||||||
|
-Encoder av1_amf `
|
||||||
|
-Hwaccel auto `
|
||||||
|
-UseHardwareWorker `
|
||||||
|
-LogDir "C:\Users\bnair\Documents\VMAFOptimiser\logs"
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Linux - same concept
|
||||||
|
./run_optimisation.sh \
|
||||||
|
--directory /media \
|
||||||
|
--vmaf 94 \
|
||||||
|
--workers 4 \
|
||||||
|
--encoder av1_amf \
|
||||||
|
--hwaccel auto \
|
||||||
|
--use-hardware-worker
|
||||||
|
```
|
||||||
|
|
||||||
|
**How it works:**
|
||||||
|
- First worker to start claims the GPU and uses `av1_amf`
|
||||||
|
- Remaining 3 workers use `svt-av1` (CPU)
|
||||||
|
- GPU worker applies +2 VMAF offset automatically to match CPU quality
|
||||||
|
|
||||||
|
### Quality Compensation
|
||||||
|
|
||||||
|
Hardware encoders produce lower quality at the same settings. The script automatically compensates:
|
||||||
|
|
||||||
|
| Target VMAF | CPU (svt-av1) | GPU (av1_amf) |
|
||||||
|
|-------------|---------------|---------------|
|
||||||
|
| 94 | Searches for VMAF 94 | Searches for VMAF 96 |
|
||||||
|
| 93 | Searches for VMAF 93 | Searches for VMAF 95 |
|
||||||
|
| 92 | Searches for VMAF 92 | Searches for VMAF 94 |
|
||||||
|
|
||||||
|
This offset (`HW_ENCODER_VMAF_OFFSET = 2.0`) can be adjusted in `optimize_library.py`.
|
||||||
|
|
||||||
### Automatic Detection
|
### Automatic Detection
|
||||||
|
|
||||||
When `--hwaccel auto` is specified, the wrapper scripts automatically select the best available hardware acceleration:
|
When `--hwaccel auto` is specified, the wrapper scripts automatically select the best available hardware acceleration:
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import signal
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from concurrent.futures import ThreadPoolExecutor, as_completed, ProcessPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor, as_completed, ProcessPoolExecutor
|
||||||
from threading import Lock
|
from threading import Lock, get_ident
|
||||||
|
|
||||||
# --- Configuration ---
|
# --- Configuration ---
|
||||||
DEFAULT_VMAF = 95.0
|
DEFAULT_VMAF = 95.0
|
||||||
@@ -23,11 +23,27 @@ TARGETS = [94.0, 93.0, 92.0, 90.0]
|
|||||||
MIN_SAVINGS_PERCENT = 12.0
|
MIN_SAVINGS_PERCENT = 12.0
|
||||||
TARGET_SAVINGS_FOR_ESTIMATE = 15.0
|
TARGET_SAVINGS_FOR_ESTIMATE = 15.0
|
||||||
|
|
||||||
|
# Hardware encoder quality compensation (GPU needs higher VMAF target to match CPU quality)
|
||||||
|
HW_ENCODER_VMAF_OFFSET = 2.0
|
||||||
|
HW_ENCODERS = {"av1_amf", "av1_nvenc", "av1_qsv", "av1_vaapi"}
|
||||||
|
|
||||||
# Global state for resume capability
|
# Global state for resume capability
|
||||||
_processed_files = set()
|
_processed_files = set()
|
||||||
_lock = Lock()
|
_lock = Lock()
|
||||||
_shutdown_requested = False
|
_shutdown_requested = False
|
||||||
_AB_AV1_HELP_CACHE = {}
|
_AB_AV1_HELP_CACHE = {}
|
||||||
|
_hw_worker_id = None # Thread ID of the designated hardware worker
|
||||||
|
|
||||||
|
|
||||||
|
def claim_hardware_worker():
|
||||||
|
"""Attempt to claim hardware worker status for this thread. Returns True if claimed."""
|
||||||
|
global _hw_worker_id
|
||||||
|
with _lock:
|
||||||
|
thread_id = get_ident()
|
||||||
|
if _hw_worker_id is None:
|
||||||
|
_hw_worker_id = thread_id
|
||||||
|
return True
|
||||||
|
return _hw_worker_id == thread_id
|
||||||
|
|
||||||
|
|
||||||
def signal_handler(signum, frame):
|
def signal_handler(signum, frame):
|
||||||
@@ -202,15 +218,30 @@ def run_command_streaming(cmd, description=""):
|
|||||||
return process.returncode
|
return process.returncode
|
||||||
|
|
||||||
|
|
||||||
def run_crf_search(filepath, target_vmaf, preset, temp_dir, use_hw=False, hwaccel=None):
|
def run_crf_search(
|
||||||
|
filepath,
|
||||||
|
target_vmaf,
|
||||||
|
preset,
|
||||||
|
temp_dir,
|
||||||
|
encoder="svt-av1",
|
||||||
|
use_hw=False,
|
||||||
|
hwaccel=None,
|
||||||
|
):
|
||||||
"""Run CRF search for a specific VMAF target"""
|
"""Run CRF search for a specific VMAF target"""
|
||||||
|
is_hw_encoder = encoder in HW_ENCODERS
|
||||||
|
|
||||||
|
# Apply VMAF offset for hardware encoders to match software quality
|
||||||
|
effective_vmaf = (
|
||||||
|
target_vmaf + HW_ENCODER_VMAF_OFFSET if is_hw_encoder else target_vmaf
|
||||||
|
)
|
||||||
|
|
||||||
cmd = [
|
cmd = [
|
||||||
"ab-av1",
|
"ab-av1",
|
||||||
"crf-search",
|
"crf-search",
|
||||||
"-i",
|
"-i",
|
||||||
str(filepath),
|
str(filepath),
|
||||||
"--min-vmaf",
|
"--min-vmaf",
|
||||||
str(target_vmaf),
|
str(effective_vmaf),
|
||||||
"--preset",
|
"--preset",
|
||||||
str(preset),
|
str(preset),
|
||||||
"--max-encoded-percent",
|
"--max-encoded-percent",
|
||||||
@@ -218,18 +249,24 @@ def run_crf_search(filepath, target_vmaf, preset, temp_dir, use_hw=False, hwacce
|
|||||||
"--temp-dir",
|
"--temp-dir",
|
||||||
temp_dir,
|
temp_dir,
|
||||||
"--samples",
|
"--samples",
|
||||||
"4", # Use 4 samples for speed/accuracy balance
|
"4",
|
||||||
]
|
]
|
||||||
|
|
||||||
# Hardware encoding support
|
# Add encoder if not default
|
||||||
|
if encoder != "svt-av1":
|
||||||
|
if ab_av1_supports("crf-search", "--encoder"):
|
||||||
|
cmd.extend(["--encoder", encoder])
|
||||||
|
|
||||||
|
# Hardware decode acceleration
|
||||||
if use_hw and hwaccel:
|
if use_hw and hwaccel:
|
||||||
if ab_av1_supports("crf-search", "--enc-input"):
|
if ab_av1_supports("crf-search", "--enc-input"):
|
||||||
cmd.extend(["--enc-input", f"hwaccel={hwaccel}"])
|
cmd.extend(["--enc-input", f"hwaccel={hwaccel}"])
|
||||||
if hwaccel == "vaapi":
|
if hwaccel == "vaapi":
|
||||||
cmd.extend(["--enc-input", "hwaccel_output_format=vaapi"])
|
cmd.extend(["--enc-input", "hwaccel_output_format=vaapi"])
|
||||||
|
|
||||||
print(f" - Searching for CRF to hit VMAF {target_vmaf}...")
|
vmaf_label = f"VMAF {effective_vmaf}" if is_hw_encoder else f"VMAF {target_vmaf}"
|
||||||
returncode = run_command_streaming(cmd, f"crf-search VMAF {target_vmaf}")
|
print(f" - Searching for CRF to hit {vmaf_label}...")
|
||||||
|
returncode = run_command_streaming(cmd, f"crf-search {vmaf_label}")
|
||||||
|
|
||||||
if returncode == 0:
|
if returncode == 0:
|
||||||
# Parse output to find CRF and predicted size
|
# Parse output to find CRF and predicted size
|
||||||
@@ -274,7 +311,13 @@ def run_crf_search(filepath, target_vmaf, preset, temp_dir, use_hw=False, hwacce
|
|||||||
|
|
||||||
|
|
||||||
def find_target_savings_params(
|
def find_target_savings_params(
|
||||||
filepath, start_vmaf, preset, temp_dir, use_hw=False, hwaccel=None
|
filepath,
|
||||||
|
start_vmaf,
|
||||||
|
preset,
|
||||||
|
temp_dir,
|
||||||
|
encoder="svt-av1",
|
||||||
|
use_hw=False,
|
||||||
|
hwaccel=None,
|
||||||
):
|
):
|
||||||
"""Find VMAF target that achieves minimum savings"""
|
"""Find VMAF target that achieves minimum savings"""
|
||||||
print(f"\n --- Finding VMAF for {TARGET_SAVINGS_FOR_ESTIMATE}% savings ---")
|
print(f"\n --- Finding VMAF for {TARGET_SAVINGS_FOR_ESTIMATE}% savings ---")
|
||||||
@@ -288,7 +331,9 @@ def find_target_savings_params(
|
|||||||
print(
|
print(
|
||||||
f" Testing VMAF {target} for {TARGET_SAVINGS_FOR_ESTIMATE}% target... (test {i + 1}/{len(test_targets)})"
|
f" Testing VMAF {target} for {TARGET_SAVINGS_FOR_ESTIMATE}% target... (test {i + 1}/{len(test_targets)})"
|
||||||
)
|
)
|
||||||
result = run_crf_search(filepath, target, preset, temp_dir, use_hw, hwaccel)
|
result = run_crf_search(
|
||||||
|
filepath, target, preset, temp_dir, encoder, use_hw, hwaccel
|
||||||
|
)
|
||||||
|
|
||||||
if result:
|
if result:
|
||||||
predicted_savings = 100.0 - result["predicted_percent"]
|
predicted_savings = 100.0 - result["predicted_percent"]
|
||||||
@@ -317,7 +362,9 @@ def find_target_savings_params(
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def run_encode(filepath, output_path, crf, preset, use_hw=False, hwaccel=None):
|
def run_encode(
|
||||||
|
filepath, output_path, crf, preset, encoder="svt-av1", use_hw=False, hwaccel=None
|
||||||
|
):
|
||||||
"""Run full encoding with real-time output streaming"""
|
"""Run full encoding with real-time output streaming"""
|
||||||
cmd = [
|
cmd = [
|
||||||
"ab-av1",
|
"ab-av1",
|
||||||
@@ -334,7 +381,10 @@ def run_encode(filepath, output_path, crf, preset, use_hw=False, hwaccel=None):
|
|||||||
"copy",
|
"copy",
|
||||||
]
|
]
|
||||||
|
|
||||||
# Hardware encoding support
|
if encoder != "svt-av1":
|
||||||
|
if ab_av1_supports("encode", "--encoder"):
|
||||||
|
cmd.extend(["--encoder", encoder])
|
||||||
|
|
||||||
if use_hw and hwaccel:
|
if use_hw and hwaccel:
|
||||||
if ab_av1_supports("encode", "--enc-input"):
|
if ab_av1_supports("encode", "--enc-input"):
|
||||||
cmd.extend(["--enc-input", f"hwaccel={hwaccel}"])
|
cmd.extend(["--enc-input", f"hwaccel={hwaccel}"])
|
||||||
@@ -401,10 +451,26 @@ def refresh_plex(plex_url, plex_token):
|
|||||||
print(f" ⚠️ Failed to refresh Plex: {e}")
|
print(f" ⚠️ Failed to refresh Plex: {e}")
|
||||||
|
|
||||||
|
|
||||||
def process_file(filepath, log_dir, log_name, preset, use_hw=False, hwaccel=None):
|
def process_file(
|
||||||
|
filepath,
|
||||||
|
log_dir,
|
||||||
|
log_name,
|
||||||
|
preset,
|
||||||
|
hw_encoder="svt-av1",
|
||||||
|
use_hw_mode=False,
|
||||||
|
hwaccel=None,
|
||||||
|
):
|
||||||
"""Process a single video file with intelligent VMAF targeting"""
|
"""Process a single video file with intelligent VMAF targeting"""
|
||||||
global _shutdown_requested
|
global _shutdown_requested
|
||||||
|
|
||||||
|
# Determine if THIS worker should use hardware encoder
|
||||||
|
use_hw = False
|
||||||
|
if use_hw_mode and hwaccel and hw_encoder in HW_ENCODERS:
|
||||||
|
use_hw = claim_hardware_worker()
|
||||||
|
|
||||||
|
# HW worker uses hardware encoder; CPU workers use svt-av1
|
||||||
|
encoder = hw_encoder if use_hw else "svt-av1"
|
||||||
|
|
||||||
filepath = Path(filepath)
|
filepath = Path(filepath)
|
||||||
lock_file = Path(log_dir).parent / ".lock" / f"{filepath.name}.lock"
|
lock_file = Path(log_dir).parent / ".lock" / f"{filepath.name}.lock"
|
||||||
|
|
||||||
@@ -449,21 +515,21 @@ def process_file(filepath, log_dir, log_name, preset, use_hw=False, hwaccel=None
|
|||||||
# Step 1: Try VMAF 94
|
# Step 1: Try VMAF 94
|
||||||
print(f"\n [Step 1] Testing VMAF 94...")
|
print(f"\n [Step 1] Testing VMAF 94...")
|
||||||
search_result_94 = run_crf_search(
|
search_result_94 = run_crf_search(
|
||||||
filepath, 94.0, preset, str(temp_dir), use_hw, hwaccel
|
filepath, 94.0, preset, str(temp_dir), encoder, use_hw, hwaccel
|
||||||
)
|
)
|
||||||
|
|
||||||
if not search_result_94:
|
if not search_result_94:
|
||||||
print(f" !! Could not hit VMAF 94")
|
print(f" !! Could not hit VMAF 94")
|
||||||
search_result_94 = run_crf_search(
|
search_result_94 = run_crf_search(
|
||||||
filepath, 93.0, preset, str(temp_dir), use_hw, hwaccel
|
filepath, 93.0, preset, str(temp_dir), encoder, use_hw, hwaccel
|
||||||
)
|
)
|
||||||
if not search_result_94:
|
if not search_result_94:
|
||||||
search_result_94 = run_crf_search(
|
search_result_94 = run_crf_search(
|
||||||
filepath, 92.0, preset, str(temp_dir), use_hw, hwaccel
|
filepath, 92.0, preset, str(temp_dir), encoder, use_hw, hwaccel
|
||||||
)
|
)
|
||||||
if not search_result_94:
|
if not search_result_94:
|
||||||
search_result_94 = run_crf_search(
|
search_result_94 = run_crf_search(
|
||||||
filepath, 90.0, preset, str(temp_dir), use_hw, hwaccel
|
filepath, 90.0, preset, str(temp_dir), encoder, use_hw, hwaccel
|
||||||
)
|
)
|
||||||
|
|
||||||
if not search_result_94:
|
if not search_result_94:
|
||||||
@@ -499,7 +565,7 @@ def process_file(filepath, log_dir, log_name, preset, use_hw=False, hwaccel=None
|
|||||||
)
|
)
|
||||||
|
|
||||||
search_result_93 = run_crf_search(
|
search_result_93 = run_crf_search(
|
||||||
filepath, 93.0, preset, str(temp_dir), use_hw, hwaccel
|
filepath, 93.0, preset, str(temp_dir), encoder, use_hw, hwaccel
|
||||||
)
|
)
|
||||||
if search_result_93:
|
if search_result_93:
|
||||||
predicted_savings_93 = 100.0 - search_result_93["predicted_percent"]
|
predicted_savings_93 = 100.0 - search_result_93["predicted_percent"]
|
||||||
@@ -524,7 +590,7 @@ def process_file(filepath, log_dir, log_name, preset, use_hw=False, hwaccel=None
|
|||||||
f" → Finding VMAF for {TARGET_SAVINGS_FOR_ESTIMATE}% savings..."
|
f" → Finding VMAF for {TARGET_SAVINGS_FOR_ESTIMATE}% savings..."
|
||||||
)
|
)
|
||||||
target_result = find_target_savings_params(
|
target_result = find_target_savings_params(
|
||||||
filepath, 93.0, preset, str(temp_dir), use_hw, hwaccel
|
filepath, 93.0, preset, str(temp_dir), encoder, use_hw, hwaccel
|
||||||
)
|
)
|
||||||
|
|
||||||
provide_recommendations(
|
provide_recommendations(
|
||||||
@@ -559,7 +625,13 @@ def process_file(filepath, log_dir, log_name, preset, use_hw=False, hwaccel=None
|
|||||||
|
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
res = run_encode(
|
res = run_encode(
|
||||||
filepath, temp_output, encode_params["crf"], preset, use_hw, hwaccel
|
filepath,
|
||||||
|
temp_output,
|
||||||
|
encode_params["crf"],
|
||||||
|
preset,
|
||||||
|
encoder,
|
||||||
|
use_hw,
|
||||||
|
hwaccel,
|
||||||
)
|
)
|
||||||
|
|
||||||
if res != 0:
|
if res != 0:
|
||||||
@@ -688,10 +760,18 @@ def main():
|
|||||||
"Examples: auto, vaapi, d3d11va, videotoolbox. Use 'none' to disable."
|
"Examples: auto, vaapi, d3d11va, videotoolbox. Use 'none' to disable."
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--encoder",
|
||||||
|
default="svt-av1",
|
||||||
|
help=(
|
||||||
|
"Video encoder to use. Default: svt-av1 (CPU). "
|
||||||
|
"Hardware encoders: av1_amf (AMD), av1_nvenc (NVIDIA), av1_qsv (Intel)."
|
||||||
|
),
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--use-hardware-worker",
|
"--use-hardware-worker",
|
||||||
action="store_true",
|
action="store_true",
|
||||||
help="Use 1 hardware encoding worker + rest CPU workers (requires --hwaccel)",
|
help="Use 1 hardware encoding worker + rest CPU workers (requires --encoder with HW encoder)",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--plex-url",
|
"--plex-url",
|
||||||
@@ -763,7 +843,9 @@ def main():
|
|||||||
fail_count = 0
|
fail_count = 0
|
||||||
|
|
||||||
# Hardware worker configuration
|
# Hardware worker configuration
|
||||||
use_hw_primary = args.use_hardware_worker and hwaccel is not None
|
# HW worker uses specified encoder; CPU workers use svt-av1
|
||||||
|
hw_encoder = args.encoder if args.encoder in HW_ENCODERS else None
|
||||||
|
use_hw_primary = args.use_hardware_worker and hw_encoder is not None
|
||||||
|
|
||||||
if args.workers == 1:
|
if args.workers == 1:
|
||||||
# Single thread - just process files
|
# Single thread - just process files
|
||||||
@@ -772,7 +854,13 @@ def main():
|
|||||||
break
|
break
|
||||||
processed_count += 1
|
processed_count += 1
|
||||||
result = process_file(
|
result = process_file(
|
||||||
file_path, args.log_dir, log_name, args.preset, use_hw_primary, hwaccel
|
file_path,
|
||||||
|
args.log_dir,
|
||||||
|
log_name,
|
||||||
|
args.preset,
|
||||||
|
args.encoder,
|
||||||
|
use_hw_primary,
|
||||||
|
hwaccel,
|
||||||
)
|
)
|
||||||
if result:
|
if result:
|
||||||
success_count += 1
|
success_count += 1
|
||||||
@@ -786,15 +874,16 @@ def main():
|
|||||||
if _shutdown_requested:
|
if _shutdown_requested:
|
||||||
break
|
break
|
||||||
|
|
||||||
# Use hardware for first file, CPU for rest
|
# All workers try to claim HW; only the first thread succeeds
|
||||||
use_hw_for_this = use_hw_primary and len(futures) == 0
|
# and will use HW for ALL its tasks
|
||||||
future = executor.submit(
|
future = executor.submit(
|
||||||
process_file,
|
process_file,
|
||||||
file_path,
|
file_path,
|
||||||
args.log_dir,
|
args.log_dir,
|
||||||
log_name,
|
log_name,
|
||||||
args.preset,
|
args.preset,
|
||||||
use_hw_for_this,
|
args.encoder,
|
||||||
|
use_hw_primary,
|
||||||
hwaccel,
|
hwaccel,
|
||||||
)
|
)
|
||||||
futures.append(future)
|
futures.append(future)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ param(
|
|||||||
[int]$Workers = 1,
|
[int]$Workers = 1,
|
||||||
[int]$Samples = 4,
|
[int]$Samples = 4,
|
||||||
[string]$Hwaccel = "",
|
[string]$Hwaccel = "",
|
||||||
|
[string]$Encoder = "svt-av1",
|
||||||
[switch]$UseHardwareWorker,
|
[switch]$UseHardwareWorker,
|
||||||
[string]$PlexUrl = "",
|
[string]$PlexUrl = "",
|
||||||
[string]$PlexToken = "",
|
[string]$PlexToken = "",
|
||||||
@@ -27,7 +28,7 @@ function Invoke-OptimizeLibrary {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
$pythonCmd = Get-Command python3, python, py | Select-Object -FirstProperty Path -ErrorAction SilentlyContinue
|
$pythonCmd = Get-Command python3, python, py -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||||
if (-not $pythonCmd) {
|
if (-not $pythonCmd) {
|
||||||
Write-ColorOutput -Message "ERROR: Python 3 not found. Please install Python 3." -Color "Red"
|
Write-ColorOutput -Message "ERROR: Python 3 not found. Please install Python 3." -Color "Red"
|
||||||
exit 1
|
exit 1
|
||||||
@@ -40,6 +41,7 @@ function Invoke-OptimizeLibrary {
|
|||||||
"--preset", $Preset.ToString(),
|
"--preset", $Preset.ToString(),
|
||||||
"--workers", $Workers.ToString(),
|
"--workers", $Workers.ToString(),
|
||||||
"--samples", $Samples.ToString(),
|
"--samples", $Samples.ToString(),
|
||||||
|
"--encoder", $Encoder,
|
||||||
"--log-dir", $LogDir
|
"--log-dir", $LogDir
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -65,11 +67,12 @@ function Invoke-OptimizeLibrary {
|
|||||||
Write-ColorOutput -Message " Preset: $Preset" -Color "White"
|
Write-ColorOutput -Message " Preset: $Preset" -Color "White"
|
||||||
Write-ColorOutput -Message " Workers: $Workers" -Color "White"
|
Write-ColorOutput -Message " Workers: $Workers" -Color "White"
|
||||||
Write-ColorOutput -Message " Samples: $Samples" -Color "White"
|
Write-ColorOutput -Message " Samples: $Samples" -Color "White"
|
||||||
|
Write-ColorOutput -Message " Encoder: $Encoder" -Color "White"
|
||||||
if ($Hwaccel) {
|
if ($Hwaccel) {
|
||||||
Write-ColorOutput -Message " HW Accel: $Hwaccel" -Color "White"
|
Write-ColorOutput -Message " HW Accel: $Hwaccel" -Color "White"
|
||||||
}
|
}
|
||||||
if ($UseHardwareWorker) {
|
if ($UseHardwareWorker) {
|
||||||
Write-ColorOutput -Message " Hardware worker: Enabled" -Color "White"
|
Write-ColorOutput -Message " Hardware worker: Enabled (1 HW + $($Workers - 1) CPU)" -Color "White"
|
||||||
}
|
}
|
||||||
if ($PlexUrl -and $PlexToken) {
|
if ($PlexUrl -and $PlexToken) {
|
||||||
Write-ColorOutput -Message " Plex refresh: Enabled" -Color "White"
|
Write-ColorOutput -Message " Plex refresh: Enabled" -Color "White"
|
||||||
|
|||||||
Reference in New Issue
Block a user