视频格式转换功能 - 实现 images_to_video() 图像序列转视频 - 实现 video_to_images() 视频转图像序列 - 支持多种图像格式 (PNG, JPG, TIFF, BMP) - 智能帧序列处理和命名 - 质量预设和编码参数优化 视频超分辨率处理 - 实现 upscale_video() 完整超分辨率功能 - 支持所有 16 种 Topaz AI 模型 - 参数验证和模型约束检查 - GPU 加速和编码优化 - 自动 Topaz FFmpeg 滤镜构建 帧插值功能 - 实现 interpolate_video() 帧插值处理 - 支持所有 4 种插值模型 - 智能 FPS 计算和目标帧率设置 - 高质量慢动作效果生成 - 参数验证和范围检查 组合处理流水线 - 实现 enhance_video() 组合增强功能 - 支持超分辨率 + 插值的完整流水线 - 智能中间文件管理 - 灵活的处理组合选项 - 自动临时文件清理 便捷处理函数 - quick_upscale_video() 一键视频放大 - auto_enhance_video() 智能自动增强 - 自动 Topaz 检测和配置 - 基于视频特征的参数选择 - 默认高质量设置 预设参数系统 - VideoUpscaleParams::for_old_video() 老视频修复 - VideoUpscaleParams::for_game_content() 游戏内容 - VideoUpscaleParams::for_animation() 动画内容 - VideoUpscaleParams::for_portrait() 人像视频 - InterpolationParams::for_slow_motion() 慢动作 - InterpolationParams::for_animation() 动画插值 完整示例和演示 - 创建 video_processing.rs 综合示例 - 展示所有视频处理场景 - 参数配置和模型选择演示 - 格式转换和组合处理演示 - 便捷函数使用演示 技术特性 - 完整的 Topaz Video AI 集成 - 智能参数验证和错误处理 - 进度回调支持 (基础实现) - 异步处理和资源管理 - 跨平台兼容性 代码质量 - 所有测试通过 (6/6 单元测试 + 1 文档测试) - 完整的错误处理和验证 - 内存安全的资源管理 - 清晰的 API 设计 功能覆盖 - 视频超分辨率 (16 种模型) - 帧插值 (4 种模型) - 格式转换 (图像序列 视频) - 组合处理流水线 - 便捷处理函数 - 智能参数预设 下一步: 开始阶段四 - 图片处理功能实现
306 lines
9.4 KiB
Rust
306 lines
9.4 KiB
Rust
//! 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<u32>,
|
|
}
|
|
|
|
/// Combined parameters for video enhancement
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct VideoEnhanceParams {
|
|
pub upscale: Option<VideoUpscaleParams>,
|
|
pub interpolation: Option<InterpolationParams>,
|
|
}
|
|
|
|
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<ProcessResult, TvaiError> {
|
|
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<ProcessResult, TvaiError> {
|
|
// 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<ProcessResult, TvaiError> {
|
|
// 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
|
|
}
|