203 lines
6.2 KiB
Rust
203 lines
6.2 KiB
Rust
//! Utility functions and system detection
|
|
|
|
pub mod temp;
|
|
pub mod gpu;
|
|
pub mod performance;
|
|
pub mod model_manager;
|
|
|
|
// Re-export main types
|
|
pub use temp::TempFileManager;
|
|
pub use gpu::{GpuManager, DetailedGpuInfo, GpuDevice, GpuSettings, GpuBenchmarkResult};
|
|
pub use model_manager::{ModelManager, ModelInfo, ModelType, ValidationReport};
|
|
pub use performance::{PerformanceMonitor, PerformanceMetrics, PerformanceSettings, ProcessingMode, PerformanceSummary, optimize_for_system};
|
|
|
|
use std::path::{Path, PathBuf};
|
|
use std::time::Duration;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use crate::core::TvaiError;
|
|
use crate::video::VideoUpscaleParams;
|
|
|
|
/// 列出可用与缺失模型(便捷函数)
|
|
pub fn list_available_models() -> Result<(Vec<ModelInfo>, Vec<String>), TvaiError> {
|
|
if let Some(topaz) = detect_topaz_installation() {
|
|
let mm = ModelManager::new(&topaz)?;
|
|
let all = mm.get_all_models()?;
|
|
let downloaded = mm.get_downloaded_models()?;
|
|
Ok((all, downloaded))
|
|
} else {
|
|
Err(TvaiError::TopazNotFound("Topaz Video AI not found".into()))
|
|
}
|
|
}
|
|
|
|
/// 校验一组所需模型并给出替代建议
|
|
pub fn validate_models(required: &[&str]) -> Result<ValidationReport, TvaiError> {
|
|
if let Some(topaz) = detect_topaz_installation() {
|
|
let mm = ModelManager::new(&topaz)?;
|
|
mm.validate_models(required)
|
|
} else {
|
|
Err(TvaiError::TopazNotFound("Topaz Video AI not found".into()))
|
|
}
|
|
}
|
|
|
|
/// GPU information
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct GpuInfo {
|
|
pub available: bool,
|
|
pub cuda_available: bool,
|
|
pub opencl_available: bool,
|
|
pub device_name: Option<String>,
|
|
pub memory_gb: Option<f32>,
|
|
}
|
|
|
|
/// FFmpeg information
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct FfmpegInfo {
|
|
pub system_available: bool,
|
|
pub topaz_available: bool,
|
|
pub system_version: Option<String>,
|
|
pub topaz_version: Option<String>,
|
|
pub system_path: Option<PathBuf>,
|
|
pub topaz_path: Option<PathBuf>,
|
|
}
|
|
|
|
/// Video file information
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct VideoInfo {
|
|
pub duration: Duration,
|
|
pub width: u32,
|
|
pub height: u32,
|
|
pub fps: f32,
|
|
pub codec: String,
|
|
pub bitrate: Option<u64>,
|
|
pub file_size: u64,
|
|
}
|
|
|
|
/// Image file information
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct ImageInfo {
|
|
pub width: u32,
|
|
pub height: u32,
|
|
pub format: String,
|
|
pub color_depth: u32,
|
|
pub file_size: u64,
|
|
}
|
|
|
|
/// Detect Topaz Video AI installation
|
|
pub fn detect_topaz_installation() -> Option<PathBuf> {
|
|
let common_paths = if cfg!(windows) {
|
|
vec![
|
|
PathBuf::from(r"C:\Program Files\Topaz Labs LLC\Topaz Video AI"),
|
|
PathBuf::from(r"C:\Program Files (x86)\Topaz Labs LLC\Topaz Video AI"),
|
|
]
|
|
} else if cfg!(target_os = "macos") {
|
|
vec![
|
|
PathBuf::from("/Applications/Topaz Video AI.app/Contents/MacOS"),
|
|
]
|
|
} else {
|
|
vec![
|
|
PathBuf::from("/opt/topaz-video-ai"),
|
|
PathBuf::from("/usr/local/bin/topaz-video-ai"),
|
|
]
|
|
};
|
|
|
|
for path in common_paths {
|
|
if path.exists() {
|
|
let ffmpeg_path = path.join(if cfg!(windows) { "ffmpeg.exe" } else { "ffmpeg" });
|
|
if ffmpeg_path.exists() {
|
|
return Some(path);
|
|
}
|
|
}
|
|
}
|
|
|
|
None
|
|
}
|
|
|
|
/// Detect GPU support
|
|
pub fn detect_gpu_support() -> GpuInfo {
|
|
// This is a simplified implementation
|
|
// In a real implementation, you would check for CUDA/OpenCL
|
|
GpuInfo {
|
|
available: true, // Assume available for now
|
|
cuda_available: true,
|
|
opencl_available: true,
|
|
device_name: Some("Unknown GPU".to_string()),
|
|
memory_gb: Some(8.0),
|
|
}
|
|
}
|
|
|
|
/// Detect FFmpeg installations
|
|
pub fn detect_ffmpeg() -> FfmpegInfo {
|
|
let topaz_path = detect_topaz_installation();
|
|
let topaz_available = topaz_path.is_some();
|
|
let topaz_ffmpeg_path = topaz_path.as_ref().map(|p| p.join("ffmpeg.exe"));
|
|
|
|
// Check system FFmpeg
|
|
let system_available = std::process::Command::new("ffmpeg")
|
|
.arg("-version")
|
|
.output()
|
|
.map(|output| output.status.success())
|
|
.unwrap_or(false);
|
|
|
|
FfmpegInfo {
|
|
system_available,
|
|
topaz_available,
|
|
system_version: None, // Would be populated by actual version check
|
|
topaz_version: None, // Would be populated by actual version check
|
|
system_path: if system_available { Some(PathBuf::from("ffmpeg")) } else { None },
|
|
topaz_path: topaz_ffmpeg_path,
|
|
}
|
|
}
|
|
|
|
/// Get video file information
|
|
pub async fn get_video_info(path: &Path) -> Result<VideoInfo, TvaiError> {
|
|
if !path.exists() {
|
|
return Err(TvaiError::FileNotFound(path.display().to_string()));
|
|
}
|
|
|
|
// This would use FFprobe to get actual video information
|
|
// For now, return placeholder data
|
|
Ok(VideoInfo {
|
|
duration: Duration::from_secs(60),
|
|
width: 1920,
|
|
height: 1080,
|
|
fps: 30.0,
|
|
codec: "h264".to_string(),
|
|
bitrate: Some(5000000),
|
|
file_size: std::fs::metadata(path)?.len(),
|
|
})
|
|
}
|
|
|
|
/// Get image file information
|
|
pub fn get_image_info(path: &Path) -> Result<ImageInfo, TvaiError> {
|
|
if !path.exists() {
|
|
return Err(TvaiError::FileNotFound(path.display().to_string()));
|
|
}
|
|
|
|
// This would use an image library to get actual image information
|
|
// For now, return placeholder data
|
|
Ok(ImageInfo {
|
|
width: 1920,
|
|
height: 1080,
|
|
format: "PNG".to_string(),
|
|
color_depth: 24,
|
|
file_size: std::fs::metadata(path)?.len(),
|
|
})
|
|
}
|
|
|
|
/// Estimate processing time for video upscaling
|
|
pub fn estimate_processing_time(
|
|
input_info: &VideoInfo,
|
|
params: &VideoUpscaleParams,
|
|
) -> Duration {
|
|
// Simple estimation based on resolution and duration
|
|
let pixels = input_info.width as f64 * input_info.height as f64;
|
|
let scale_factor = params.scale_factor as f64;
|
|
let duration_secs = input_info.duration.as_secs_f64();
|
|
|
|
// Rough estimation: 1 second per megapixel per second of video
|
|
let estimated_secs = (pixels * scale_factor * duration_secs) / 1_000_000.0;
|
|
|
|
Duration::from_secs_f64(estimated_secs.max(1.0))
|
|
}
|