//! Video processing functionality pub mod upscale; pub mod interpolation; pub mod converter; use std::path::Path; use serde::{Deserialize, Serialize}; use crate::core::{TvaiError, ProcessResult, TvaiProcessor, ProgressCallback}; use crate::config::{UpscaleModel, InterpolationModel, QualityPreset}; /// Parameters for video upscaling #[derive(Debug, Clone, Serialize, Deserialize)] pub struct VideoUpscaleParams { pub scale_factor: f32, pub model: UpscaleModel, pub compression: f32, pub blend: f32, pub quality_preset: QualityPreset, } /// Parameters for frame interpolation #[derive(Debug, Clone, Serialize, Deserialize)] pub struct InterpolationParams { pub input_fps: u32, pub multiplier: f32, pub model: InterpolationModel, pub target_fps: Option, } /// Combined parameters for video enhancement #[derive(Debug, Clone, Serialize, Deserialize)] pub struct VideoEnhanceParams { pub upscale: Option, pub interpolation: Option, } impl VideoUpscaleParams { /// Create parameters optimized for old video content pub fn for_old_video() -> Self { Self { scale_factor: 2.0, model: UpscaleModel::Thf4, compression: 0.3, blend: 0.2, quality_preset: QualityPreset::HighQuality, } } /// Create parameters optimized for game content pub fn for_game_content() -> Self { Self { scale_factor: 2.0, model: UpscaleModel::Ghq5, compression: 0.0, blend: 0.0, quality_preset: QualityPreset::HighQuality, } } /// Create parameters optimized for animation pub fn for_animation() -> Self { Self { scale_factor: 2.0, model: UpscaleModel::Iris3, compression: -0.1, blend: 0.1, quality_preset: QualityPreset::HighQuality, } } /// Create parameters optimized for portrait video pub fn for_portrait() -> Self { Self { scale_factor: 2.0, model: UpscaleModel::Nyx3, compression: -0.2, blend: 0.1, quality_preset: QualityPreset::HighQuality, } } } impl InterpolationParams { /// Create parameters for smooth slow motion pub fn for_slow_motion(input_fps: u32, multiplier: f32) -> Self { Self { input_fps, multiplier, model: InterpolationModel::Apo8, target_fps: None, } } /// Create parameters for animation interpolation pub fn for_animation(input_fps: u32, multiplier: f32) -> Self { Self { input_fps, multiplier, model: InterpolationModel::Chr2, target_fps: None, } } } /// Enhanced video processing with both upscaling and interpolation impl TvaiProcessor { /// Enhance video with combined upscaling and interpolation pub async fn enhance_video( &mut self, input_path: &Path, output_path: &Path, params: VideoEnhanceParams, progress_callback: Option<&ProgressCallback>, ) -> Result { let start_time = std::time::Instant::now(); // Validate inputs self.validate_input_file(input_path)?; self.validate_output_path(output_path)?; let operation_id = self.generate_operation_id(); let mut current_input = input_path.to_path_buf(); let mut intermediate_files = Vec::new(); if let Some(callback) = progress_callback { callback(0.0); } // Step 1: Apply upscaling if requested if let Some(upscale_params) = ¶ms.upscale { let intermediate_output = self.create_temp_path(&operation_id, "upscaled.mp4"); intermediate_files.push(intermediate_output.clone()); // For now, pass None for progress callback to avoid lifetime issues // TODO: Implement proper progress callback forwarding self.upscale_video( ¤t_input, &intermediate_output, upscale_params.clone(), None, ).await?; if let Some(callback) = progress_callback { callback(0.5); } current_input = intermediate_output; } if let Some(callback) = progress_callback { callback(0.5); } // Step 2: Apply interpolation if requested if let Some(interpolation_params) = ¶ms.interpolation { // For now, pass None for progress callback to avoid lifetime issues // TODO: Implement proper progress callback forwarding let result = self.interpolate_video( ¤t_input, output_path, interpolation_params.clone(), None, ).await?; // Clean up intermediate files self.cleanup_temp_files(&operation_id)?; return Ok(result); } // If only upscaling was requested, move the result to final output if params.upscale.is_some() && params.interpolation.is_none() { std::fs::rename(¤t_input, output_path)?; } else { return Err(TvaiError::InvalidParameter( "At least one enhancement (upscale or interpolation) must be specified".to_string() )); } let processing_time = start_time.elapsed(); // Create combined metadata let mut metadata = self.create_metadata( operation_id, input_path, format!("enhance: upscale={}, interpolation={}", params.upscale.is_some(), params.interpolation.is_some() ), ); metadata.ffmpeg_version = self.get_ffmpeg_version(true).await.ok(); if let Some(callback) = progress_callback { callback(1.0); } Ok(ProcessResult { output_path: output_path.to_path_buf(), processing_time, metadata, }) } } /// Quick video upscaling function pub async fn quick_upscale_video( input: &Path, output: &Path, scale: f32, ) -> Result { // Detect Topaz installation let topaz_path = crate::utils::detect_topaz_installation() .ok_or_else(|| TvaiError::TopazNotFound("Topaz Video AI not found".to_string()))?; // Create default configuration let config = crate::core::TvaiConfig::builder() .topaz_path(topaz_path) .use_gpu(true) .build()?; // Create processor let mut processor = TvaiProcessor::new(config)?; // Create default upscaling parameters let params = VideoUpscaleParams { scale_factor: scale, model: crate::config::UpscaleModel::Iris3, // Best general purpose model compression: 0.0, blend: 0.0, quality_preset: crate::config::QualityPreset::HighQuality, }; // Perform upscaling processor.upscale_video(input, output, params, None).await } /// Automatic video enhancement pub async fn auto_enhance_video( input: &Path, output: &Path, ) -> Result { // Detect Topaz installation let topaz_path = crate::utils::detect_topaz_installation() .ok_or_else(|| TvaiError::TopazNotFound("Topaz Video AI not found".to_string()))?; // Create default configuration let config = crate::core::TvaiConfig::builder() .topaz_path(topaz_path) .use_gpu(true) .build()?; // Create processor let mut processor = TvaiProcessor::new(config)?; // Get video info to determine best enhancement strategy let video_info = crate::utils::get_video_info(input).await?; // Auto-determine enhancement parameters based on video characteristics let mut enhance_params = VideoEnhanceParams { upscale: None, interpolation: None, }; // Apply upscaling if resolution is low if video_info.width < 1920 || video_info.height < 1080 { let scale_factor = if video_info.width <= 720 { 2.0 } else { 1.5 }; enhance_params.upscale = Some(VideoUpscaleParams { scale_factor, model: crate::config::UpscaleModel::Iris3, compression: 0.0, blend: 0.1, quality_preset: crate::config::QualityPreset::HighQuality, }); } // Apply interpolation if frame rate is low if video_info.fps < 30.0 { let multiplier = if video_info.fps <= 15.0 { 2.0 } else { 1.5 }; enhance_params.interpolation = Some(InterpolationParams { input_fps: video_info.fps as u32, multiplier, model: crate::config::InterpolationModel::Apo8, target_fps: None, }); } // If no enhancement is needed, just copy the file if enhance_params.upscale.is_none() && enhance_params.interpolation.is_none() { std::fs::copy(input, output)?; return Ok(ProcessResult { output_path: output.to_path_buf(), processing_time: std::time::Duration::from_millis(0), metadata: processor.create_metadata( processor.generate_operation_id(), input, "auto_enhance: no enhancement needed".to_string(), ), }); } // Perform enhancement processor.enhance_video(input, output, enhance_params, None).await }