//! Main processor for Topaz Video AI operations use std::path::{Path, PathBuf}; use std::time::Duration; use serde::{Deserialize, Serialize}; use uuid::Uuid; use crate::core::{TvaiError, FfmpegManager}; /// Main processor for Topaz Video AI operations #[derive(Debug)] pub struct TvaiProcessor { config: TvaiConfig, ffmpeg_manager: FfmpegManager, temp_dir: PathBuf, } /// Configuration for TvaiProcessor #[derive(Debug, Clone)] pub struct TvaiConfig { /// Path to Topaz Video AI installation pub topaz_path: PathBuf, /// Whether to use GPU acceleration pub use_gpu: bool, /// Custom temporary directory (optional) pub temp_dir: Option, /// Force use of Topaz FFmpeg even for non-AI operations pub force_topaz_ffmpeg: bool, } /// Result of a processing operation #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ProcessResult { /// Path to the output file pub output_path: PathBuf, /// Time taken for processing pub processing_time: Duration, /// Additional metadata about the processing pub metadata: ProcessMetadata, } /// Metadata about a processing operation #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ProcessMetadata { /// Unique operation ID pub operation_id: String, /// Input file path pub input_path: PathBuf, /// Processing parameters used pub parameters: String, /// Whether GPU was used pub used_gpu: bool, /// FFmpeg version used pub ffmpeg_version: Option, } impl TvaiConfig { /// Create a new configuration builder pub fn builder() -> TvaiConfigBuilder { TvaiConfigBuilder::default() } /// Create a configuration with default settings pub fn new(topaz_path: PathBuf) -> Self { Self { topaz_path, use_gpu: true, temp_dir: None, force_topaz_ffmpeg: true, } } } /// Builder for TvaiConfig #[derive(Debug, Default)] pub struct TvaiConfigBuilder { topaz_path: Option, use_gpu: Option, temp_dir: Option, force_topaz_ffmpeg: Option, } impl TvaiConfigBuilder { /// Set the Topaz Video AI installation path pub fn topaz_path>(mut self, path: P) -> Self { self.topaz_path = Some(path.as_ref().to_path_buf()); self } /// Set whether to use GPU acceleration pub fn use_gpu(mut self, use_gpu: bool) -> Self { self.use_gpu = Some(use_gpu); self } /// Set custom temporary directory pub fn temp_dir>(mut self, path: P) -> Self { self.temp_dir = Some(path.as_ref().to_path_buf()); self } /// Set whether to force Topaz FFmpeg usage pub fn force_topaz_ffmpeg(mut self, force: bool) -> Self { self.force_topaz_ffmpeg = Some(force); self } /// Build the configuration pub fn build(self) -> Result { let topaz_path = self.topaz_path .ok_or_else(|| TvaiError::InvalidParameter("topaz_path is required".to_string()))?; if !topaz_path.exists() { return Err(TvaiError::TopazNotFound(topaz_path.display().to_string())); } Ok(TvaiConfig { topaz_path, use_gpu: self.use_gpu.unwrap_or(true), temp_dir: self.temp_dir, force_topaz_ffmpeg: self.force_topaz_ffmpeg.unwrap_or(true), }) } } impl TvaiProcessor { /// Create a new processor with the given configuration pub fn new(config: TvaiConfig) -> Result { let ffmpeg_manager = FfmpegManager::new( Some(&config.topaz_path), config.force_topaz_ffmpeg, ); // Verify Topaz FFmpeg is available for AI operations if !ffmpeg_manager.is_topaz_available() { return Err(TvaiError::TopazNotFound( config.topaz_path.display().to_string() )); } // Set up temporary directory let temp_dir = match &config.temp_dir { Some(dir) => { std::fs::create_dir_all(dir)?; dir.clone() } None => { let temp_dir = std::env::temp_dir().join("tvai_temp"); std::fs::create_dir_all(&temp_dir)?; temp_dir } }; Ok(Self { config, ffmpeg_manager, temp_dir, }) } /// Get the configuration pub fn config(&self) -> &TvaiConfig { &self.config } /// Get the FFmpeg manager pub fn ffmpeg_manager(&self) -> &FfmpegManager { &self.ffmpeg_manager } /// Get the temporary directory pub fn temp_dir(&self) -> &Path { &self.temp_dir } /// Generate a unique operation ID pub fn generate_operation_id(&self) -> String { Uuid::new_v4().to_string() } /// Create a temporary file path with the given extension pub fn create_temp_path(&self, operation_id: &str, suffix: &str) -> PathBuf { self.temp_dir.join(format!("{}_{}", operation_id, suffix)) } /// Clean up temporary files for an operation pub fn cleanup_temp_files(&self, operation_id: &str) -> Result<(), TvaiError> { let pattern = format!("{}_", operation_id); if let Ok(entries) = std::fs::read_dir(&self.temp_dir) { for entry in entries.flatten() { if let Some(name) = entry.file_name().to_str() { if name.starts_with(&pattern) { let _ = std::fs::remove_file(entry.path()); } } } } Ok(()) } /// Check if GPU is available and enabled pub fn is_gpu_enabled(&self) -> bool { self.config.use_gpu && self.is_gpu_available() } /// Check if GPU is available on the system pub fn is_gpu_available(&self) -> bool { // This is a simplified check - in a real implementation, // you might want to check for CUDA/OpenCL availability self.config.use_gpu } } impl Drop for TvaiProcessor { fn drop(&mut self) { // Clean up temporary directory if it was created by us if self.config.temp_dir.is_none() { let _ = std::fs::remove_dir_all(&self.temp_dir); } } }