//! 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}; /// 音频处理模式 #[derive(Debug, Clone, Serialize, Deserialize)] pub enum AudioMode { /// 保留原音频 Keep, /// 移除音频 Remove, /// 重新编码音频 Reencode { codec: String, bitrate: u32 }, } /// 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, // 高级TVAI参数 pub preblur: f32, // 预模糊 (0-100) pub noise: f32, // 噪点减少 (0-100) pub details: f32, // 细节恢复 (0-100) pub halo: f32, // 光晕减少 (0-100) pub blur: f32, // 模糊减少 (0-100) pub estimate: u32, // 估算质量 (1-20) pub device: i32, // 设备ID (-2=auto, -1=CPU, 0+=GPU) pub vram: u32, // VRAM使用 (0-1) pub instances: u32, // 实例数量 (1-4) // 输出尺寸控制 pub target_width: Option, // 目标宽度 pub target_height: Option, // 目标高度 pub maintain_aspect: bool, // 保持宽高比 pub pad_color: String, // 填充颜色 // 编码参数 pub codec: Option, // 编码器 (h264_nvenc, hevc_nvenc, libx264等) pub profile: Option, // 编码配置文件 pub pixel_format: String, // 像素格式 pub gop_size: u32, // GOP大小 pub preset: Option, // 编码预设 pub tune: Option, // 调优选项 pub rate_control: String, // 码率控制模式 pub quality_param: u32, // 质量参数 (CRF/QP) pub lookahead: u32, // 前瞻帧数 pub spatial_aq: bool, // 空间自适应量化 pub aq_strength: u32, // AQ强度 pub bitrate: u32, // 目标码率 (0=VBR) pub buffer_frames: u32, // 缓冲帧数 // 音频处理 pub audio_mode: AudioMode, // 音频处理模式 // 元数据 pub preserve_metadata: bool, // 保留元数据 pub custom_metadata: Option, // 自定义元数据 } /// 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 Default for VideoUpscaleParams { fn default() -> Self { Self { // 基础参数 scale_factor: 2.0, model: UpscaleModel::Iris3, compression: 0.0, blend: 0.0, quality_preset: QualityPreset::HighQuality, // 高级TVAI参数 preblur: 0.0, noise: 0.0, details: 0.0, halo: 0.0, blur: 0.0, estimate: 8, device: -2, // 自动选择 vram: 1, instances: 1, // 输出尺寸控制 target_width: None, target_height: None, maintain_aspect: true, pad_color: "black".to_string(), // 编码参数 codec: None, // 自动选择 profile: Some("high".to_string()), pixel_format: "yuv420p".to_string(), gop_size: 30, preset: Some("p7".to_string()), tune: Some("hq".to_string()), rate_control: "constqp".to_string(), quality_param: 18, lookahead: 20, spatial_aq: true, aq_strength: 15, bitrate: 0, // VBR buffer_frames: 0, // 音频处理 audio_mode: AudioMode::Keep, // 元数据 preserve_metadata: true, custom_metadata: None, } } } 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, preblur: 0.0, noise: 20.0, details: 30.0, halo: 10.0, blur: 15.0, ..Default::default() } } /// 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, preblur: 0.0, noise: 0.0, details: 50.0, halo: 0.0, blur: 0.0, quality_param: 15, // 更高质量 ..Default::default() } } /// Create parameters optimized for animation pub fn for_animation() -> Self { Self { scale_factor: 2.0, model: UpscaleModel::Iris3, compression: -0.1, blend: 0.1, preblur: 0.0, noise: 5.0, details: 25.0, halo: 5.0, blur: 10.0, ..Default::default() } } /// 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, preblur: 0.0, noise: 15.0, details: 40.0, halo: 20.0, blur: 25.0, ..Default::default() } } /// Create parameters for maximum quality (slow processing) pub fn for_maximum_quality() -> Self { Self { scale_factor: 2.0, model: UpscaleModel::Ahq12, compression: 0.0, blend: 0.0, preblur: 0.0, noise: 30.0, details: 60.0, halo: 30.0, blur: 40.0, estimate: 20, // 最高估算质量 quality_param: 12, // 最高质量 lookahead: 32, instances: 1, // 单实例确保质量 ..Default::default() } } /// Create parameters for fast processing pub fn for_fast_processing() -> Self { Self { scale_factor: 2.0, model: UpscaleModel::Alqs2, compression: 0.2, blend: 0.0, preblur: 0.0, noise: 10.0, details: 20.0, halo: 5.0, blur: 10.0, estimate: 4, // 较低估算质量 quality_param: 22, // 较低质量但更快 preset: Some("p1".to_string()), // 最快预设 instances: 2, // 多实例加速 ..Default::default() } } } 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 { quick_upscale_video_with_model(input, output, scale, None).await } /// Quick video upscaling function with model selection pub async fn quick_upscale_video_with_model( input: &Path, output: &Path, scale: f32, model: Option, ) -> 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 upscaling parameters with specified or default model let params = VideoUpscaleParams { scale_factor: scale, model: model.unwrap_or(crate::config::UpscaleModel::Iris3), // Use specified model or default to Iris3 compression: 0.0, blend: 0.0, quality_preset: crate::config::QualityPreset::HighQuality, ..Default::default() }; // 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, ..Default::default() }); } // 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 } /// Quick video interpolation function pub async fn quick_interpolate_video( input: &Path, output: &Path, multiplier: f32, input_fps: u32, ) -> 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 interpolation parameters let params = InterpolationParams { input_fps, multiplier, model: crate::config::InterpolationModel::Apo8, // Best general purpose interpolation model target_fps: None, // Auto-calculate based on multiplier }; // Perform interpolation processor.interpolate_video(input, output, params, None).await } /// Process video using a Topaz template pub async fn process_with_template( input: &Path, output: &Path, template_name: &str, ) -> Result { // Get template manager let manager = crate::config::global_topaz_templates().lock() .map_err(|_| TvaiError::ConfigurationError("Failed to access template manager".to_string()))?; // Apply template let applied = manager.apply_template(template_name)?; drop(manager); // Release lock early // 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)?; // Process video with template parameters processor.enhance_video(input, output, applied.enhance_params, None).await } /// List all available templates pub fn list_available_templates() -> Vec { let manager = crate::config::global_topaz_templates().lock() .unwrap_or_else(|_| panic!("Failed to access template manager")); manager.list_templates() } /// Get template information pub fn get_template_info(template_name: &str) -> Option<(String, String)> { let manager = crate::config::global_topaz_templates().lock() .unwrap_or_else(|_| panic!("Failed to access template manager")); manager.get_template(template_name) .map(|template| (template.name.clone(), template.description.clone())) } /// Quick functions for common templates pub async fn upscale_to_4k(input: &Path, output: &Path) -> Result { process_with_template(input, output, "upscale_to_4k").await } pub async fn convert_to_60fps(input: &Path, output: &Path) -> Result { process_with_template(input, output, "convert_to_60fps").await } pub async fn remove_noise(input: &Path, output: &Path) -> Result { process_with_template(input, output, "remove_noise").await } pub async fn slow_motion_4x(input: &Path, output: &Path) -> Result { process_with_template(input, output, "4x_slow_motion").await } pub async fn auto_crop_stabilization(input: &Path, output: &Path) -> Result { process_with_template(input, output, "auto_crop_stabilization").await }