Files
Pac-cogs/videoarchiver/ffmpeg/gpu_detector.py
pacnpal 8503fc6fdd Enhanced FFmpeg Integration:
Added robust error handling and logging
Improved binary verification and initialization
Added proper GPU detection and hardware acceleration
Optimized encoding parameters for different content types
Improved File Operations:

Added retry mechanisms for file operations
Enhanced temporary directory management
Improved cleanup of failed downloads
Added proper permission handling
Enhanced Queue Management:

Fixed queue manager initialization
Added better error recovery
Improved status tracking and logging
Enhanced cleanup of failed items
Better Error Handling:

Added comprehensive exception hierarchy
Improved error logging and reporting
Added fallback mechanisms for failures
Enhanced error recovery strategies
2024-11-15 03:21:25 +00:00

272 lines
10 KiB
Python

"""GPU detection functionality for FFmpeg"""
import os
import subprocess
import logging
import platform
import re
from typing import Dict, List
from pathlib import Path
logger = logging.getLogger("VideoArchiver")
class GPUDetector:
def __init__(self, ffmpeg_path: Path):
"""Initialize GPU detector
Args:
ffmpeg_path: Path to FFmpeg binary
"""
self.ffmpeg_path = Path(ffmpeg_path)
if not self.ffmpeg_path.exists():
raise FileNotFoundError(f"FFmpeg not found at {self.ffmpeg_path}")
def detect_gpu(self) -> Dict[str, bool]:
"""Detect available GPU acceleration support
Returns:
Dict containing boolean flags for each GPU type
"""
gpu_info = {
"nvidia": False,
"amd": False,
"intel": False
}
try:
# Check system-specific GPU detection first
system = platform.system().lower()
if system == "windows":
gpu_info.update(self._detect_windows_gpu())
elif system == "linux":
gpu_info.update(self._detect_linux_gpu())
elif system == "darwin":
gpu_info.update(self._detect_macos_gpu())
# Verify GPU support in FFmpeg
gpu_info.update(self._verify_ffmpeg_gpu_support())
# Log detection results
detected_gpus = [name for name, detected in gpu_info.items() if detected]
if detected_gpus:
logger.info(f"Detected GPUs: {', '.join(detected_gpus)}")
else:
logger.info("No GPU acceleration support detected")
return gpu_info
except Exception as e:
logger.error(f"Error during GPU detection: {str(e)}")
return {"nvidia": False, "amd": False, "intel": False}
def _detect_windows_gpu(self) -> Dict[str, bool]:
"""Detect GPUs on Windows using PowerShell"""
gpu_info = {"nvidia": False, "amd": False, "intel": False}
try:
# Use PowerShell to get GPU info
cmd = ["powershell", "-Command", "Get-WmiObject Win32_VideoController | Select-Object Name"]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
if result.returncode == 0:
output = result.stdout.lower()
gpu_info["nvidia"] = "nvidia" in output
gpu_info["amd"] = any(x in output for x in ["amd", "radeon"])
gpu_info["intel"] = "intel" in output
except Exception as e:
logger.error(f"Windows GPU detection failed: {str(e)}")
return gpu_info
def _detect_linux_gpu(self) -> Dict[str, bool]:
"""Detect GPUs on Linux using lspci and other tools"""
gpu_info = {"nvidia": False, "amd": False, "intel": False}
try:
# Try lspci first
try:
result = subprocess.run(
["lspci", "-v"],
capture_output=True,
text=True,
timeout=10
)
if result.returncode == 0:
output = result.stdout.lower()
gpu_info["nvidia"] = "nvidia" in output
gpu_info["amd"] = any(x in output for x in ["amd", "radeon"])
gpu_info["intel"] = "intel" in output
except FileNotFoundError:
pass
# Check for NVIDIA using nvidia-smi
if not gpu_info["nvidia"]:
try:
result = subprocess.run(
["nvidia-smi"],
capture_output=True,
timeout=10
)
gpu_info["nvidia"] = result.returncode == 0
except FileNotFoundError:
pass
# Check for AMD using rocm-smi
if not gpu_info["amd"]:
try:
result = subprocess.run(
["rocm-smi"],
capture_output=True,
timeout=10
)
gpu_info["amd"] = result.returncode == 0
except FileNotFoundError:
pass
# Check for Intel using intel_gpu_top
if not gpu_info["intel"]:
try:
result = subprocess.run(
["intel_gpu_top", "-L"],
capture_output=True,
timeout=10
)
gpu_info["intel"] = result.returncode == 0
except FileNotFoundError:
pass
except Exception as e:
logger.error(f"Linux GPU detection failed: {str(e)}")
return gpu_info
def _detect_macos_gpu(self) -> Dict[str, bool]:
"""Detect GPUs on macOS using system_profiler"""
gpu_info = {"nvidia": False, "amd": False, "intel": False}
try:
cmd = ["system_profiler", "SPDisplaysDataType"]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
if result.returncode == 0:
output = result.stdout.lower()
gpu_info["nvidia"] = "nvidia" in output
gpu_info["amd"] = any(x in output for x in ["amd", "radeon"])
gpu_info["intel"] = "intel" in output
except Exception as e:
logger.error(f"macOS GPU detection failed: {str(e)}")
return gpu_info
def _verify_ffmpeg_gpu_support(self) -> Dict[str, bool]:
"""Verify GPU support in FFmpeg installation"""
gpu_support = {"nvidia": False, "amd": False, "intel": False}
try:
# Check FFmpeg encoders
cmd = [str(self.ffmpeg_path), "-hide_banner", "-encoders"]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
if result.returncode == 0:
output = result.stdout.lower()
# Check for specific GPU encoders
gpu_support["nvidia"] = "h264_nvenc" in output
gpu_support["amd"] = "h264_amf" in output
gpu_support["intel"] = "h264_qsv" in output
# Log available encoders
encoders = []
if gpu_support["nvidia"]:
encoders.append("NVENC")
if gpu_support["amd"]:
encoders.append("AMF")
if gpu_support["intel"]:
encoders.append("QSV")
if encoders:
logger.info(f"FFmpeg supports GPU encoders: {', '.join(encoders)}")
else:
logger.info("No GPU encoders available in FFmpeg")
except Exception as e:
logger.error(f"FFmpeg GPU support verification failed: {str(e)}")
return gpu_support
def get_gpu_info(self) -> Dict[str, List[str]]:
"""Get detailed GPU information
Returns:
Dict containing lists of GPU names by type
"""
gpu_info = {
"nvidia": [],
"amd": [],
"intel": []
}
try:
system = platform.system().lower()
if system == "windows":
cmd = ["powershell", "-Command", "Get-WmiObject Win32_VideoController | Select-Object Name"]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
if result.returncode == 0:
for line in result.stdout.splitlines():
line = line.strip().lower()
if line:
if "nvidia" in line:
gpu_info["nvidia"].append(line)
elif any(x in line for x in ["amd", "radeon"]):
gpu_info["amd"].append(line)
elif "intel" in line:
gpu_info["intel"].append(line)
elif system == "linux":
try:
result = subprocess.run(
["lspci", "-v"],
capture_output=True,
text=True,
timeout=10
)
if result.returncode == 0:
for line in result.stdout.splitlines():
if "vga" in line.lower() or "3d" in line.lower():
if "nvidia" in line.lower():
gpu_info["nvidia"].append(line.strip())
elif any(x in line.lower() for x in ["amd", "radeon"]):
gpu_info["amd"].append(line.strip())
elif "intel" in line.lower():
gpu_info["intel"].append(line.strip())
except FileNotFoundError:
pass
elif system == "darwin":
cmd = ["system_profiler", "SPDisplaysDataType"]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
if result.returncode == 0:
current_gpu = None
for line in result.stdout.splitlines():
line = line.strip().lower()
if "chipset model" in line:
if "nvidia" in line:
current_gpu = "nvidia"
gpu_info["nvidia"].append(line.split(":")[1].strip())
elif any(x in line for x in ["amd", "radeon"]):
current_gpu = "amd"
gpu_info["amd"].append(line.split(":")[1].strip())
elif "intel" in line:
current_gpu = "intel"
gpu_info["intel"].append(line.split(":")[1].strip())
except Exception as e:
logger.error(f"Error getting detailed GPU info: {str(e)}")
return gpu_info