You've already forked FrameTour-RenderWorker
- 定义硬件加速类型常量(none、qsv、cuda) - 配置QSV和CUDA编码参数及预设 - 在WorkerConfig中添加硬件加速配置选项 - 实现基于硬件加速类型的编码参数动态获取 - 添加FFmpeg硬件加速解码和滤镜参数 - 检测并报告系统硬件加速支持信息 - 在API客户端中上报硬件加速配置和支持状态
267 lines
6.7 KiB
Python
267 lines
6.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
系统信息工具
|
|
|
|
提供系统信息采集功能。
|
|
"""
|
|
|
|
import os
|
|
import platform
|
|
import subprocess
|
|
from typing import Optional, Dict, Any
|
|
|
|
import psutil
|
|
from constant import SOFTWARE_VERSION, DEFAULT_CAPABILITIES, HW_ACCEL_NONE, HW_ACCEL_QSV, HW_ACCEL_CUDA
|
|
|
|
|
|
def get_sys_info():
|
|
"""
|
|
获取系统信息
|
|
|
|
Returns:
|
|
dict: 系统信息字典
|
|
"""
|
|
mem = psutil.virtual_memory()
|
|
|
|
info = {
|
|
'os': platform.system(),
|
|
'cpu': f"{os.cpu_count()} cores",
|
|
'memory': f"{mem.total // (1024**3)}GB",
|
|
'cpuUsage': f"{psutil.cpu_percent()}%",
|
|
'memoryAvailable': f"{mem.available // (1024**3)}GB",
|
|
'platform': platform.system(),
|
|
'pythonVersion': platform.python_version(),
|
|
'version': SOFTWARE_VERSION,
|
|
}
|
|
|
|
# 尝试获取 GPU 信息
|
|
gpu_info = get_gpu_info()
|
|
if gpu_info:
|
|
info['gpu'] = gpu_info
|
|
|
|
return info
|
|
|
|
|
|
def get_capabilities():
|
|
"""
|
|
获取 Worker 支持的能力列表
|
|
|
|
Returns:
|
|
list: 能力列表
|
|
"""
|
|
return DEFAULT_CAPABILITIES.copy()
|
|
|
|
|
|
def get_gpu_info() -> Optional[str]:
|
|
"""
|
|
尝试获取 GPU 信息
|
|
|
|
Returns:
|
|
str: GPU 信息,失败返回 None
|
|
"""
|
|
try:
|
|
# 尝试使用 nvidia-smi
|
|
result = subprocess.run(
|
|
['nvidia-smi', '--query-gpu=name', '--format=csv,noheader'],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=5
|
|
)
|
|
if result.returncode == 0:
|
|
gpu_name = result.stdout.strip().split('\n')[0]
|
|
return gpu_name
|
|
except Exception:
|
|
pass
|
|
|
|
return None
|
|
|
|
|
|
def get_ffmpeg_version() -> str:
|
|
"""
|
|
获取 FFmpeg 版本
|
|
|
|
Returns:
|
|
str: FFmpeg 版本号
|
|
"""
|
|
try:
|
|
result = subprocess.run(
|
|
['ffmpeg', '-version'],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=5
|
|
)
|
|
if result.returncode == 0:
|
|
first_line = result.stdout.split('\n')[0]
|
|
# 解析版本号,例如 "ffmpeg version 6.0 ..."
|
|
parts = first_line.split()
|
|
for i, part in enumerate(parts):
|
|
if part == 'version' and i + 1 < len(parts):
|
|
return parts[i + 1]
|
|
except Exception:
|
|
pass
|
|
|
|
return 'unknown'
|
|
|
|
|
|
def check_ffmpeg_encoder(encoder: str) -> bool:
|
|
"""
|
|
检查 FFmpeg 是否支持指定的编码器
|
|
|
|
Args:
|
|
encoder: 编码器名称,如 'h264_nvenc', 'h264_qsv'
|
|
|
|
Returns:
|
|
bool: 是否支持该编码器
|
|
"""
|
|
try:
|
|
result = subprocess.run(
|
|
['ffmpeg', '-hide_banner', '-encoders'],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=5
|
|
)
|
|
if result.returncode == 0:
|
|
return encoder in result.stdout
|
|
except Exception:
|
|
pass
|
|
|
|
return False
|
|
|
|
|
|
def check_ffmpeg_decoder(decoder: str) -> bool:
|
|
"""
|
|
检查 FFmpeg 是否支持指定的解码器
|
|
|
|
Args:
|
|
decoder: 解码器名称,如 'h264_cuvid', 'h264_qsv'
|
|
|
|
Returns:
|
|
bool: 是否支持该解码器
|
|
"""
|
|
try:
|
|
result = subprocess.run(
|
|
['ffmpeg', '-hide_banner', '-decoders'],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=5
|
|
)
|
|
if result.returncode == 0:
|
|
return decoder in result.stdout
|
|
except Exception:
|
|
pass
|
|
|
|
return False
|
|
|
|
|
|
def check_ffmpeg_hwaccel(hwaccel: str) -> bool:
|
|
"""
|
|
检查 FFmpeg 是否支持指定的硬件加速方法
|
|
|
|
Args:
|
|
hwaccel: 硬件加速方法,如 'cuda', 'qsv', 'dxva2', 'd3d11va'
|
|
|
|
Returns:
|
|
bool: 是否支持该硬件加速方法
|
|
"""
|
|
try:
|
|
result = subprocess.run(
|
|
['ffmpeg', '-hide_banner', '-hwaccels'],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=5
|
|
)
|
|
if result.returncode == 0:
|
|
return hwaccel in result.stdout
|
|
except Exception:
|
|
pass
|
|
|
|
return False
|
|
|
|
|
|
def detect_hw_accel_support() -> Dict[str, Any]:
|
|
"""
|
|
检测系统的硬件加速支持情况
|
|
|
|
Returns:
|
|
dict: 硬件加速支持信息
|
|
{
|
|
'cuda': {
|
|
'available': bool,
|
|
'gpu': str or None,
|
|
'encoder': bool, # h264_nvenc
|
|
'decoder': bool, # h264_cuvid
|
|
},
|
|
'qsv': {
|
|
'available': bool,
|
|
'encoder': bool, # h264_qsv
|
|
'decoder': bool, # h264_qsv
|
|
},
|
|
'recommended': str # 推荐的加速方式: 'cuda', 'qsv', 'none'
|
|
}
|
|
"""
|
|
result = {
|
|
'cuda': {
|
|
'available': False,
|
|
'gpu': None,
|
|
'encoder': False,
|
|
'decoder': False,
|
|
},
|
|
'qsv': {
|
|
'available': False,
|
|
'encoder': False,
|
|
'decoder': False,
|
|
},
|
|
'recommended': HW_ACCEL_NONE
|
|
}
|
|
|
|
# 检测 CUDA/NVENC 支持
|
|
gpu_info = get_gpu_info()
|
|
if gpu_info:
|
|
result['cuda']['gpu'] = gpu_info
|
|
result['cuda']['available'] = check_ffmpeg_hwaccel('cuda')
|
|
result['cuda']['encoder'] = check_ffmpeg_encoder('h264_nvenc')
|
|
result['cuda']['decoder'] = check_ffmpeg_decoder('h264_cuvid')
|
|
|
|
# 检测 QSV 支持
|
|
result['qsv']['available'] = check_ffmpeg_hwaccel('qsv')
|
|
result['qsv']['encoder'] = check_ffmpeg_encoder('h264_qsv')
|
|
result['qsv']['decoder'] = check_ffmpeg_decoder('h264_qsv')
|
|
|
|
# 推荐硬件加速方式(优先 CUDA,其次 QSV)
|
|
if result['cuda']['available'] and result['cuda']['encoder']:
|
|
result['recommended'] = HW_ACCEL_CUDA
|
|
elif result['qsv']['available'] and result['qsv']['encoder']:
|
|
result['recommended'] = HW_ACCEL_QSV
|
|
|
|
return result
|
|
|
|
|
|
def get_hw_accel_info_str() -> str:
|
|
"""
|
|
获取硬件加速支持信息的可读字符串
|
|
|
|
Returns:
|
|
str: 硬件加速支持信息描述
|
|
"""
|
|
support = detect_hw_accel_support()
|
|
|
|
parts = []
|
|
|
|
if support['cuda']['available']:
|
|
gpu = support['cuda']['gpu'] or 'Unknown GPU'
|
|
status = 'encoder+decoder' if support['cuda']['encoder'] and support['cuda']['decoder'] else (
|
|
'encoder only' if support['cuda']['encoder'] else 'decoder only' if support['cuda']['decoder'] else 'hwaccel only'
|
|
)
|
|
parts.append(f"CUDA({gpu}, {status})")
|
|
|
|
if support['qsv']['available']:
|
|
status = 'encoder+decoder' if support['qsv']['encoder'] and support['qsv']['decoder'] else (
|
|
'encoder only' if support['qsv']['encoder'] else 'decoder only' if support['qsv']['decoder'] else 'hwaccel only'
|
|
)
|
|
parts.append(f"QSV({status})")
|
|
|
|
if not parts:
|
|
return "No hardware acceleration available"
|
|
|
|
return ', '.join(parts) + f" [recommended: {support['recommended']}]"
|