Files
mixvideo-v2/cargos/tvai/src/utils/mod.rs
2025-08-14 13:01:43 +08:00

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))
}