Files
mixvideo-v2/cargos/tvai/src/utils/mod.rs
imeepos 42e3e923f9 feat: 完成 tvai 库核心处理引擎 (阶段二)
临时文件管理系统
- 实现 TempFileManager 完整功能
- 支持操作级别的文件跟踪和清理
- 自动清理机制和手动控制选项
- UUID 生成和唯一文件路径创建
- 支持文件和目录的创建与管理

 处理器核心逻辑增强
- 集成 TempFileManager 到 TvaiProcessor
- 添加进度回调支持 (ProgressCallback)
- 实现 ProcessingOptions 配置结构
- 添加文件验证功能 (输入/输出路径)
- FFmpeg 命令执行与进度跟踪

 核心处理方法
- execute_ffmpeg_command() 带进度回调
- validate_input_file() 输入文件验证
- validate_output_path() 输出路径验证
- create_metadata() 处理元数据生成
- get_ffmpeg_version() 版本信息获取

 API 增强
- 添加 create_temp_path() 临时文件创建
- 添加 create_unique_temp_path() 唯一路径生成
- 添加 create_temp_dir() 临时目录创建
- 添加 cleanup_temp_files() 操作清理
- 添加 cleanup_all_temp_files() 全量清理

 高级示例和测试
- 创建 advanced_usage.rs 展示所有新功能
- 临时文件管理演示
- 进度回调演示
- 文件验证演示
- 系统信息获取演示

 单元测试覆盖
- TempFileManager 完整测试套件
- TvaiProcessor 核心功能测试
- 配置构建器测试
- 进度回调类型测试

 测试结果
-  所有单元测试通过 (6/6)
-  文档测试通过 (1/1)
-  高级示例运行成功
-  临时文件管理功能验证
-  进度回调机制验证

 代码质量
- 完整的错误处理
- 内存安全的资源管理
- 异步友好的 API 设计
- 全面的类型安全

下一步: 开始阶段三 - 视频处理功能实现
2025-08-11 15:33:14 +08:00

176 lines
5.0 KiB
Rust

//! Utility functions and system detection
pub mod temp;
pub mod gpu;
// Re-export main types
pub use temp::TempFileManager;
use std::path::{Path, PathBuf};
use std::time::Duration;
use serde::{Deserialize, Serialize};
use crate::core::TvaiError;
use crate::video::VideoUpscaleParams;
/// 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))
}