You've already forked FrameTour-RenderWorker
feat(video): 添加硬件加速支持
- 定义硬件加速类型常量(none、qsv、cuda) - 配置QSV和CUDA编码参数及预设 - 在WorkerConfig中添加硬件加速配置选项 - 实现基于硬件加速类型的编码参数动态获取 - 添加FFmpeg硬件加速解码和滤镜参数 - 检测并报告系统硬件加速支持信息 - 在API客户端中上报硬件加速配置和支持状态
This commit is contained in:
@@ -41,7 +41,14 @@ EFFECT_TYPES = (
|
||||
'blur', # 模糊效果(预留)
|
||||
)
|
||||
|
||||
# 统一视频编码参数(来自集成文档)
|
||||
# 硬件加速类型
|
||||
HW_ACCEL_NONE = 'none' # 纯软件编解码
|
||||
HW_ACCEL_QSV = 'qsv' # Intel Quick Sync Video (核显/独显)
|
||||
HW_ACCEL_CUDA = 'cuda' # NVIDIA NVENC/NVDEC
|
||||
|
||||
HW_ACCEL_TYPES = (HW_ACCEL_NONE, HW_ACCEL_QSV, HW_ACCEL_CUDA)
|
||||
|
||||
# 统一视频编码参数(软件编码,来自集成文档)
|
||||
VIDEO_ENCODE_PARAMS = {
|
||||
'codec': 'libx264',
|
||||
'preset': 'medium',
|
||||
@@ -51,6 +58,28 @@ VIDEO_ENCODE_PARAMS = {
|
||||
'pix_fmt': 'yuv420p',
|
||||
}
|
||||
|
||||
# QSV 硬件加速视频编码参数(Intel Quick Sync)
|
||||
VIDEO_ENCODE_PARAMS_QSV = {
|
||||
'codec': 'h264_qsv',
|
||||
'preset': 'medium', # QSV 支持: veryfast, faster, fast, medium, slow, slower, veryslow
|
||||
'profile': 'main',
|
||||
'level': '4.0',
|
||||
'global_quality': '23', # QSV 使用 global_quality 代替 crf(1-51,值越低质量越高)
|
||||
'look_ahead': '1', # 启用前瞻分析提升质量
|
||||
'pix_fmt': 'nv12', # QSV 硬件表面格式
|
||||
}
|
||||
|
||||
# CUDA 硬件加速视频编码参数(NVIDIA NVENC)
|
||||
VIDEO_ENCODE_PARAMS_CUDA = {
|
||||
'codec': 'h264_nvenc',
|
||||
'preset': 'p4', # NVENC 预设 p1-p7(p1 最快,p7 最慢/质量最高),p4 ≈ medium
|
||||
'profile': 'main',
|
||||
'level': '4.0',
|
||||
'rc': 'vbr', # 码率控制模式:vbr 可变码率
|
||||
'cq': '23', # 恒定质量模式的质量值(0-51)
|
||||
'pix_fmt': 'yuv420p', # NVENC 输入格式(会自动转换)
|
||||
}
|
||||
|
||||
# 统一音频编码参数
|
||||
AUDIO_ENCODE_PARAMS = {
|
||||
'codec': 'aac',
|
||||
|
||||
@@ -9,6 +9,8 @@ import os
|
||||
from dataclasses import dataclass, field
|
||||
from typing import List, Optional
|
||||
|
||||
from constant import HW_ACCEL_NONE, HW_ACCEL_QSV, HW_ACCEL_CUDA, HW_ACCEL_TYPES
|
||||
|
||||
|
||||
# 默认支持的任务类型
|
||||
DEFAULT_CAPABILITIES = [
|
||||
@@ -54,6 +56,9 @@ class WorkerConfig:
|
||||
download_timeout: int = 300 # 秒,下载超时
|
||||
upload_timeout: int = 600 # 秒,上传超时
|
||||
|
||||
# 硬件加速配置
|
||||
hw_accel: str = HW_ACCEL_NONE # 硬件加速类型: none, qsv, cuda
|
||||
|
||||
@classmethod
|
||||
def from_env(cls) -> 'WorkerConfig':
|
||||
"""从环境变量创建配置"""
|
||||
@@ -98,6 +103,11 @@ class WorkerConfig:
|
||||
download_timeout = int(os.getenv('DOWNLOAD_TIMEOUT', '300'))
|
||||
upload_timeout = int(os.getenv('UPLOAD_TIMEOUT', '600'))
|
||||
|
||||
# 硬件加速配置
|
||||
hw_accel = os.getenv('HW_ACCEL', HW_ACCEL_NONE).lower()
|
||||
if hw_accel not in HW_ACCEL_TYPES:
|
||||
hw_accel = HW_ACCEL_NONE
|
||||
|
||||
return cls(
|
||||
api_endpoint=api_endpoint,
|
||||
access_key=access_key,
|
||||
@@ -110,7 +120,8 @@ class WorkerConfig:
|
||||
capabilities=capabilities,
|
||||
ffmpeg_timeout=ffmpeg_timeout,
|
||||
download_timeout=download_timeout,
|
||||
upload_timeout=upload_timeout
|
||||
upload_timeout=upload_timeout,
|
||||
hw_accel=hw_accel
|
||||
)
|
||||
|
||||
def get_work_dir_path(self, task_id: str) -> str:
|
||||
@@ -120,3 +131,15 @@ class WorkerConfig:
|
||||
def ensure_temp_dir(self) -> None:
|
||||
"""确保临时目录存在"""
|
||||
os.makedirs(self.temp_dir, exist_ok=True)
|
||||
|
||||
def is_hw_accel_enabled(self) -> bool:
|
||||
"""是否启用了硬件加速"""
|
||||
return self.hw_accel != HW_ACCEL_NONE
|
||||
|
||||
def is_qsv(self) -> bool:
|
||||
"""是否使用 QSV 硬件加速"""
|
||||
return self.hw_accel == HW_ACCEL_QSV
|
||||
|
||||
def is_cuda(self) -> bool:
|
||||
"""是否使用 CUDA 硬件加速"""
|
||||
return self.hw_accel == HW_ACCEL_CUDA
|
||||
|
||||
126
handlers/base.py
126
handlers/base.py
@@ -19,6 +19,10 @@ from domain.task import Task
|
||||
from domain.result import TaskResult, ErrorCode
|
||||
from domain.config import WorkerConfig
|
||||
from services import storage
|
||||
from constant import (
|
||||
HW_ACCEL_NONE, HW_ACCEL_QSV, HW_ACCEL_CUDA,
|
||||
VIDEO_ENCODE_PARAMS, VIDEO_ENCODE_PARAMS_QSV, VIDEO_ENCODE_PARAMS_CUDA
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from services.api_client import APIClientV2
|
||||
@@ -26,15 +30,94 @@ if TYPE_CHECKING:
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# v2 统一视频编码参数(来自集成文档)
|
||||
VIDEO_ENCODE_ARGS = [
|
||||
'-c:v', 'libx264',
|
||||
'-preset', 'medium',
|
||||
'-profile:v', 'main',
|
||||
'-level', '4.0',
|
||||
'-crf', '23',
|
||||
'-pix_fmt', 'yuv420p',
|
||||
def get_video_encode_args(hw_accel: str = HW_ACCEL_NONE) -> List[str]:
|
||||
"""
|
||||
根据硬件加速配置获取视频编码参数
|
||||
|
||||
Args:
|
||||
hw_accel: 硬件加速类型 (none, qsv, cuda)
|
||||
|
||||
Returns:
|
||||
FFmpeg 视频编码参数列表
|
||||
"""
|
||||
if hw_accel == HW_ACCEL_QSV:
|
||||
params = VIDEO_ENCODE_PARAMS_QSV
|
||||
return [
|
||||
'-c:v', params['codec'],
|
||||
'-preset', params['preset'],
|
||||
'-profile:v', params['profile'],
|
||||
'-level', params['level'],
|
||||
'-global_quality', params['global_quality'],
|
||||
'-look_ahead', params['look_ahead'],
|
||||
]
|
||||
elif hw_accel == HW_ACCEL_CUDA:
|
||||
params = VIDEO_ENCODE_PARAMS_CUDA
|
||||
return [
|
||||
'-c:v', params['codec'],
|
||||
'-preset', params['preset'],
|
||||
'-profile:v', params['profile'],
|
||||
'-level', params['level'],
|
||||
'-rc', params['rc'],
|
||||
'-cq', params['cq'],
|
||||
'-b:v', '0', # 配合 vbr 模式使用 cq
|
||||
]
|
||||
else:
|
||||
# 软件编码(默认)
|
||||
params = VIDEO_ENCODE_PARAMS
|
||||
return [
|
||||
'-c:v', params['codec'],
|
||||
'-preset', params['preset'],
|
||||
'-profile:v', params['profile'],
|
||||
'-level', params['level'],
|
||||
'-crf', params['crf'],
|
||||
'-pix_fmt', params['pix_fmt'],
|
||||
]
|
||||
|
||||
|
||||
def get_hwaccel_decode_args(hw_accel: str = HW_ACCEL_NONE) -> List[str]:
|
||||
"""
|
||||
获取硬件加速解码参数(输入文件之前使用)
|
||||
|
||||
Args:
|
||||
hw_accel: 硬件加速类型 (none, qsv, cuda)
|
||||
|
||||
Returns:
|
||||
FFmpeg 硬件加速解码参数列表
|
||||
"""
|
||||
if hw_accel == HW_ACCEL_CUDA:
|
||||
# CUDA 硬件加速解码
|
||||
# 注意:使用 cuda 作为 hwaccel,但输出到系统内存以便 CPU 滤镜处理
|
||||
return ['-hwaccel', 'cuda', '-hwaccel_output_format', 'cuda']
|
||||
elif hw_accel == HW_ACCEL_QSV:
|
||||
# QSV 硬件加速解码
|
||||
return ['-hwaccel', 'qsv', '-hwaccel_output_format', 'qsv']
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def get_hwaccel_filter_prefix(hw_accel: str = HW_ACCEL_NONE) -> str:
|
||||
"""
|
||||
获取硬件加速滤镜前缀(用于 hwdownload 从 GPU 到 CPU)
|
||||
|
||||
注意:由于大多数复杂滤镜(如 lut3d, overlay, crop 等)不支持硬件表面,
|
||||
我们需要在滤镜链开始时将硬件表面下载到系统内存。
|
||||
|
||||
Args:
|
||||
hw_accel: 硬件加速类型
|
||||
|
||||
Returns:
|
||||
需要添加到滤镜链开头的 hwdownload 滤镜字符串
|
||||
"""
|
||||
if hw_accel == HW_ACCEL_CUDA:
|
||||
return 'hwdownload,format=nv12,'
|
||||
elif hw_accel == HW_ACCEL_QSV:
|
||||
return 'hwdownload,format=nv12,'
|
||||
else:
|
||||
return ''
|
||||
|
||||
|
||||
# v2 统一视频编码参数(兼容旧代码,使用软件编码)
|
||||
VIDEO_ENCODE_ARGS = get_video_encode_args(HW_ACCEL_NONE)
|
||||
|
||||
# v2 统一音频编码参数
|
||||
AUDIO_ENCODE_ARGS = [
|
||||
@@ -178,6 +261,33 @@ class BaseHandler(TaskHandler, ABC):
|
||||
self.config = config
|
||||
self.api_client = api_client
|
||||
|
||||
def get_video_encode_args(self) -> List[str]:
|
||||
"""
|
||||
获取当前配置的视频编码参数
|
||||
|
||||
Returns:
|
||||
FFmpeg 视频编码参数列表
|
||||
"""
|
||||
return get_video_encode_args(self.config.hw_accel)
|
||||
|
||||
def get_hwaccel_decode_args(self) -> List[str]:
|
||||
"""
|
||||
获取硬件加速解码参数(在输入文件之前使用)
|
||||
|
||||
Returns:
|
||||
FFmpeg 硬件加速解码参数列表
|
||||
"""
|
||||
return get_hwaccel_decode_args(self.config.hw_accel)
|
||||
|
||||
def get_hwaccel_filter_prefix(self) -> str:
|
||||
"""
|
||||
获取硬件加速滤镜前缀
|
||||
|
||||
Returns:
|
||||
需要添加到滤镜链开头的 hwdownload 滤镜字符串
|
||||
"""
|
||||
return get_hwaccel_filter_prefix(self.config.hw_accel)
|
||||
|
||||
def before_handle(self, task: Task) -> None:
|
||||
"""处理前钩子"""
|
||||
logger.debug(f"[task:{task.task_id}] Before handle: {task.task_type.value}")
|
||||
|
||||
@@ -10,7 +10,7 @@ import os
|
||||
import logging
|
||||
from typing import List, Optional
|
||||
|
||||
from handlers.base import BaseHandler, VIDEO_ENCODE_ARGS
|
||||
from handlers.base import BaseHandler
|
||||
from domain.task import Task, TaskType, TransitionConfig, TRANSITION_TYPES
|
||||
from domain.result import TaskResult, ErrorCode
|
||||
|
||||
@@ -235,8 +235,8 @@ class ComposeTransitionHandler(BaseHandler):
|
||||
'-map', '[outv]',
|
||||
]
|
||||
|
||||
# 编码参数(与片段视频一致)
|
||||
cmd.extend(VIDEO_ENCODE_ARGS)
|
||||
# 编码参数(根据硬件加速配置动态获取)
|
||||
cmd.extend(self.get_video_encode_args())
|
||||
|
||||
# 帧率
|
||||
fps = output_spec.fps
|
||||
|
||||
@@ -10,7 +10,7 @@ import os
|
||||
import logging
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
from handlers.base import BaseHandler, VIDEO_ENCODE_ARGS
|
||||
from handlers.base import BaseHandler
|
||||
from domain.task import Task, TaskType, RenderSpec, OutputSpec, Effect
|
||||
from domain.result import TaskResult, ErrorCode
|
||||
|
||||
@@ -170,6 +170,11 @@ class RenderSegmentVideoHandler(BaseHandler):
|
||||
"""
|
||||
cmd = ['ffmpeg', '-y', '-hide_banner']
|
||||
|
||||
# 硬件加速解码参数(在输入文件之前)
|
||||
hwaccel_args = self.get_hwaccel_decode_args()
|
||||
if hwaccel_args:
|
||||
cmd.extend(hwaccel_args)
|
||||
|
||||
# 输入文件
|
||||
cmd.extend(['-i', input_file])
|
||||
|
||||
@@ -196,8 +201,8 @@ class RenderSegmentVideoHandler(BaseHandler):
|
||||
elif filters:
|
||||
cmd.extend(['-vf', filters])
|
||||
|
||||
# 编码参数(v2 统一参数)
|
||||
cmd.extend(VIDEO_ENCODE_ARGS)
|
||||
# 编码参数(根据硬件加速配置动态获取)
|
||||
cmd.extend(self.get_video_encode_args())
|
||||
|
||||
# 帧率
|
||||
fps = output_spec.fps
|
||||
@@ -253,6 +258,12 @@ class RenderSegmentVideoHandler(BaseHandler):
|
||||
effects = render_spec.get_effects()
|
||||
has_camera_shot = any(e.effect_type == 'cameraShot' for e in effects)
|
||||
|
||||
# 硬件加速时需要先 hwdownload(将 GPU 表面下载到系统内存)
|
||||
hwaccel_prefix = self.get_hwaccel_filter_prefix()
|
||||
if hwaccel_prefix:
|
||||
# 去掉末尾的逗号,作为第一个滤镜
|
||||
filters.append(hwaccel_prefix.rstrip(','))
|
||||
|
||||
# 1. 变速处理
|
||||
speed = float(render_spec.speed) if render_spec.speed else 1.0
|
||||
if speed != 1.0 and speed > 0:
|
||||
@@ -304,7 +315,8 @@ class RenderSegmentVideoHandler(BaseHandler):
|
||||
fps=fps,
|
||||
has_overlay=has_overlay,
|
||||
overlap_head_ms=overlap_head_ms,
|
||||
overlap_tail_ms=overlap_tail_ms
|
||||
overlap_tail_ms=overlap_tail_ms,
|
||||
use_hwdownload=bool(hwaccel_prefix)
|
||||
)
|
||||
|
||||
# 6. 帧冻结(tpad)- 用于转场 overlap 区域
|
||||
@@ -337,7 +349,8 @@ class RenderSegmentVideoHandler(BaseHandler):
|
||||
fps: int,
|
||||
has_overlay: bool = False,
|
||||
overlap_head_ms: int = 0,
|
||||
overlap_tail_ms: int = 0
|
||||
overlap_tail_ms: int = 0,
|
||||
use_hwdownload: bool = False
|
||||
) -> str:
|
||||
"""
|
||||
构建包含特效的 filter_complex 滤镜图
|
||||
@@ -351,6 +364,7 @@ class RenderSegmentVideoHandler(BaseHandler):
|
||||
has_overlay: 是否有叠加层
|
||||
overlap_head_ms: 头部 overlap 时长
|
||||
overlap_tail_ms: 尾部 overlap 时长
|
||||
use_hwdownload: 是否使用了硬件加速解码(已在 base_filters 中包含 hwdownload)
|
||||
|
||||
Returns:
|
||||
filter_complex 格式的滤镜字符串
|
||||
|
||||
@@ -12,6 +12,7 @@ from typing import Dict, List, Optional, Any
|
||||
|
||||
from domain.task import Task
|
||||
from domain.config import WorkerConfig
|
||||
from util.system import get_hw_accel_info_str
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -338,7 +339,9 @@ class APIClientV2:
|
||||
'cpu': f"{psutil.cpu_count()} cores",
|
||||
'memory': f"{psutil.virtual_memory().total // (1024**3)}GB",
|
||||
'cpuUsage': f"{psutil.cpu_percent()}%",
|
||||
'memoryAvailable': f"{psutil.virtual_memory().available // (1024**3)}GB"
|
||||
'memoryAvailable': f"{psutil.virtual_memory().available // (1024**3)}GB",
|
||||
'hwAccelConfig': self.config.hw_accel, # 当前配置的硬件加速
|
||||
'hwAccelSupport': get_hw_accel_info_str(), # 系统支持的硬件加速
|
||||
}
|
||||
|
||||
# 尝试获取 GPU 信息
|
||||
|
||||
167
util/system.py
167
util/system.py
@@ -8,10 +8,10 @@
|
||||
import os
|
||||
import platform
|
||||
import subprocess
|
||||
from typing import Optional
|
||||
from typing import Optional, Dict, Any
|
||||
|
||||
import psutil
|
||||
from constant import SOFTWARE_VERSION, DEFAULT_CAPABILITIES
|
||||
from constant import SOFTWARE_VERSION, DEFAULT_CAPABILITIES, HW_ACCEL_NONE, HW_ACCEL_QSV, HW_ACCEL_CUDA
|
||||
|
||||
|
||||
def get_sys_info():
|
||||
@@ -101,3 +101,166 @@ def get_ffmpeg_version() -> str:
|
||||
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']}]"
|
||||
|
||||
Reference in New Issue
Block a user