mixvideo-v2/cargos/tvai/src/core/processor.rs

224 lines
6.4 KiB
Rust

//! 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<PathBuf>,
/// 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<String>,
}
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<PathBuf>,
use_gpu: Option<bool>,
temp_dir: Option<PathBuf>,
force_topaz_ffmpeg: Option<bool>,
}
impl TvaiConfigBuilder {
/// Set the Topaz Video AI installation path
pub fn topaz_path<P: AsRef<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<P: AsRef<Path>>(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<TvaiConfig, TvaiError> {
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<Self, TvaiError> {
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);
}
}
}