Files
mixvideo-v2/cargos/tvai/src/video/mod.rs
imeepos c683557307 feat: 完成 tvai 库视频处理功能 (阶段三)
视频格式转换功能
- 实现 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 种模型)
-  格式转换 (图像序列  视频)
-  组合处理流水线
-  便捷处理函数
-  智能参数预设

下一步: 开始阶段四 - 图片处理功能实现
2025-08-11 15:43:38 +08:00

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) = &params.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(
&current_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) = &params.interpolation {
// For now, pass None for progress callback to avoid lifetime issues
// TODO: Implement proper progress callback forwarding
let result = self.interpolate_video(
&current_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(&current_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
}