优化 ffmpeg 硬件加速 独显 兼容性

This commit is contained in:
linyq 2025-05-19 02:50:23 +08:00
parent 47cd4f145d
commit 8fda320d50
2 changed files with 108 additions and 16 deletions

View File

@ -216,21 +216,32 @@ def process_single_video(
use_software_encoder = True
if hwaccel:
if hwaccel == 'cuda' or hwaccel == 'nvenc':
# 获取硬件加速类型和编码器信息
hwaccel_type = ffmpeg_utils.get_ffmpeg_hwaccel_type()
hwaccel_encoder = ffmpeg_utils.get_ffmpeg_hwaccel_encoder()
if hwaccel_type == 'cuda' or hwaccel_type == 'nvenc':
try:
# 在使用NVIDIA编码器前先检查其可用性
subprocess.run(['ffmpeg', '-hide_banner', '-encoders'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
command.extend(['-c:v', 'h264_nvenc', '-preset', 'p4', '-profile:v', 'high'])
use_software_encoder = False
except Exception:
logger.warning("NVENC编码器不可用将使用软件编码")
elif hwaccel == 'qsv' and not is_windows: # 在Windows上避免使用QSV
# 检查NVENC编码器是否可用
encoders_cmd = subprocess.run(
["ffmpeg", "-hide_banner", "-encoders"],
stderr=subprocess.PIPE, stdout=subprocess.PIPE, text=True, check=False
)
if "h264_nvenc" in encoders_cmd.stdout.lower():
command.extend(['-c:v', 'h264_nvenc', '-preset', 'p4', '-profile:v', 'high'])
use_software_encoder = False
else:
logger.warning("NVENC编码器不可用将使用软件编码")
except Exception as e:
logger.warning(f"NVENC编码器检测失败: {str(e)},将使用软件编码")
elif hwaccel_type == 'qsv':
command.extend(['-c:v', 'h264_qsv', '-preset', 'medium'])
use_software_encoder = False
elif hwaccel == 'videotoolbox': # macOS
elif hwaccel_type == 'videotoolbox': # macOS
command.extend(['-c:v', 'h264_videotoolbox', '-profile:v', 'high'])
use_software_encoder = False
elif hwaccel == 'vaapi' and not is_windows: # Linux VA-API
elif hwaccel_type == 'vaapi': # Linux VA-API
command.extend(['-c:v', 'h264_vaapi', '-profile', '100'])
use_software_encoder = False

View File

@ -138,18 +138,48 @@ def _detect_windows_acceleration(supported_hwaccels: str) -> None:
# 检测NVIDIA CUDA支持
if 'cuda' in supported_hwaccels and 'nvidia' in gpu_info.lower():
# 添加调试日志
logger.debug(f"Windows检测到NVIDIA显卡尝试CUDA加速")
try:
test_cmd = subprocess.run(
["ffmpeg", "-hwaccel", "cuda", "-i", "/dev/null", "-f", "null", "-"],
# 先检查NVENC编码器是否可用
encoders_cmd = subprocess.run(
["ffmpeg", "-hide_banner", "-encoders"],
stderr=subprocess.PIPE, stdout=subprocess.PIPE, text=True, check=False
)
if test_cmd.returncode == 0:
has_nvenc = "h264_nvenc" in encoders_cmd.stdout.lower()
logger.debug(f"NVENC编码器检测结果: {'可用' if has_nvenc else '不可用'}")
# 测试CUDA硬件加速
test_cmd = subprocess.run(
["ffmpeg", "-hwaccel", "cuda", "-i", "NUL", "-f", "null", "-t", "0.1", "-"],
stderr=subprocess.PIPE, stdout=subprocess.PIPE, text=True, check=False
)
# 记录详细的返回信息以便调试
logger.debug(f"CUDA测试返回码: {test_cmd.returncode}")
logger.debug(f"CUDA测试错误输出: {test_cmd.stderr[:200]}..." if len(test_cmd.stderr) > 200 else f"CUDA测试错误输出: {test_cmd.stderr}")
if test_cmd.returncode == 0 or has_nvenc:
_FFMPEG_HW_ACCEL_INFO["available"] = True
_FFMPEG_HW_ACCEL_INFO["type"] = "cuda"
_FFMPEG_HW_ACCEL_INFO["encoder"] = "h264_nvenc"
_FFMPEG_HW_ACCEL_INFO["hwaccel_args"] = ["-hwaccel", "cuda"]
_FFMPEG_HW_ACCEL_INFO["is_dedicated_gpu"] = True
return
# 如果上面的测试失败,尝试另一种方式
test_cmd2 = subprocess.run(
["ffmpeg", "-hide_banner", "-loglevel", "error", "-hwaccel", "cuda", "-hwaccel_output_format", "cuda", "-i", "NUL", "-f", "null", "-t", "0.1", "-"],
stderr=subprocess.PIPE, stdout=subprocess.PIPE, text=True, check=False
)
if test_cmd2.returncode == 0:
_FFMPEG_HW_ACCEL_INFO["available"] = True
_FFMPEG_HW_ACCEL_INFO["type"] = "cuda"
_FFMPEG_HW_ACCEL_INFO["encoder"] = "h264_nvenc"
_FFMPEG_HW_ACCEL_INFO["hwaccel_args"] = ["-hwaccel", "cuda", "-hwaccel_output_format", "cuda"]
_FFMPEG_HW_ACCEL_INFO["is_dedicated_gpu"] = True
return
except Exception as e:
logger.debug(f"测试CUDA失败: {str(e)}")
@ -172,11 +202,16 @@ def _detect_windows_acceleration(supported_hwaccels: str) -> None:
# 检测D3D11VA支持
if 'd3d11va' in supported_hwaccels:
logger.debug("Windows尝试D3D11VA加速")
try:
test_cmd = subprocess.run(
["ffmpeg", "-hwaccel", "d3d11va", "-i", "/dev/null", "-f", "null", "-"],
["ffmpeg", "-hwaccel", "d3d11va", "-i", "NUL", "-f", "null", "-t", "0.1", "-"],
stderr=subprocess.PIPE, stdout=subprocess.PIPE, text=True, check=False
)
# 记录详细的返回信息以便调试
logger.debug(f"D3D11VA测试返回码: {test_cmd.returncode}")
if test_cmd.returncode == 0:
_FFMPEG_HW_ACCEL_INFO["available"] = True
_FFMPEG_HW_ACCEL_INFO["type"] = "d3d11va"
@ -189,11 +224,16 @@ def _detect_windows_acceleration(supported_hwaccels: str) -> None:
# 检测DXVA2支持
if 'dxva2' in supported_hwaccels:
logger.debug("Windows尝试DXVA2加速")
try:
test_cmd = subprocess.run(
["ffmpeg", "-hwaccel", "dxva2", "-i", "/dev/null", "-f", "null", "-"],
["ffmpeg", "-hwaccel", "dxva2", "-i", "NUL", "-f", "null", "-t", "0.1", "-"],
stderr=subprocess.PIPE, stdout=subprocess.PIPE, text=True, check=False
)
# 记录详细的返回信息以便调试
logger.debug(f"DXVA2测试返回码: {test_cmd.returncode}")
if test_cmd.returncode == 0:
_FFMPEG_HW_ACCEL_INFO["available"] = True
_FFMPEG_HW_ACCEL_INFO["type"] = "dxva2"
@ -204,6 +244,36 @@ def _detect_windows_acceleration(supported_hwaccels: str) -> None:
except Exception as e:
logger.debug(f"测试DXVA2失败: {str(e)}")
# 如果检测到NVIDIA显卡但前面的测试都失败尝试直接使用NVENC编码器
if 'nvidia' in gpu_info.lower():
logger.debug("Windows检测到NVIDIA显卡尝试直接使用NVENC编码器")
try:
# 检查NVENC编码器是否可用
encoders_cmd = subprocess.run(
["ffmpeg", "-hide_banner", "-encoders"],
stderr=subprocess.PIPE, stdout=subprocess.PIPE, text=True, check=False
)
if "h264_nvenc" in encoders_cmd.stdout.lower():
logger.debug("NVENC编码器可用尝试直接使用")
# 测试NVENC编码器
test_cmd = subprocess.run(
["ffmpeg", "-f", "lavfi", "-i", "color=c=black:s=640x360:r=30", "-c:v", "h264_nvenc", "-t", "0.1", "-f", "null", "-"],
stderr=subprocess.PIPE, stdout=subprocess.PIPE, text=True, check=False
)
logger.debug(f"NVENC编码器测试返回码: {test_cmd.returncode}")
if test_cmd.returncode == 0:
_FFMPEG_HW_ACCEL_INFO["available"] = True
_FFMPEG_HW_ACCEL_INFO["type"] = "nvenc"
_FFMPEG_HW_ACCEL_INFO["encoder"] = "h264_nvenc"
_FFMPEG_HW_ACCEL_INFO["hwaccel_args"] = [] # 不使用hwaccel参数直接使用编码器
_FFMPEG_HW_ACCEL_INFO["is_dedicated_gpu"] = True
return
except Exception as e:
logger.debug(f"测试NVENC编码器失败: {str(e)}")
_FFMPEG_HW_ACCEL_INFO["message"] = f"Windows系统未检测到可用的硬件加速显卡信息: {gpu_info}"
@ -295,10 +365,21 @@ def _get_windows_gpu_info() -> str:
str: 显卡信息字符串
"""
try:
# 使用PowerShell获取更可靠的显卡信息
gpu_info = subprocess.run(
['wmic', 'path', 'win32_VideoController', 'get', 'name'],
['powershell', '-Command', "Get-WmiObject Win32_VideoController | Select-Object Name | Format-List"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False
)
# 如果PowerShell失败尝试使用wmic
if not gpu_info.stdout.strip():
gpu_info = subprocess.run(
['wmic', 'path', 'win32_VideoController', 'get', 'name'],
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False
)
# 记录详细的显卡信息以便调试
logger.debug(f"Windows显卡信息: {gpu_info.stdout}")
return gpu_info.stdout
except Exception as e:
logger.warning(f"获取Windows显卡信息失败: {str(e)}")