feat: 扩展TVAI高级参数并修复编译错误

主要功能:
- 将TVAI可控参数从5个扩展到34个 (+29个新参数)
- 支持完整的FFmpeg编码参数控制
- 添加高级TVAI AI增强参数 (preblur, noise, details, halo, blur等)
- 支持输出尺寸控制和音频处理模式

 技术改进:
- 重新设计VideoUpscaleParams结构体
- 添加智能默认值和预设系统
- 优化参数验证和错误处理
- 改进FFmpeg滤镜构建逻辑

 修复编译错误:
- 修复E0063结构体字段缺失错误 (6处)
- 修复E0597生命周期错误 (3处)
- 消除未使用代码警告 (2处)
- 确保向后兼容性

 文档:
- 详细的高级参数使用指南
- 完整的编译错误修复总结
- 34个参数的分类和说明
This commit is contained in:
imeepos
2025-08-11 19:06:49 +08:00
parent f3c06cc777
commit 0a742f1e6b
9 changed files with 966 additions and 33 deletions

View File

@@ -67,6 +67,7 @@ impl PresetManager {
compression: 0.0,
blend: 0.1,
quality_preset: QualityPreset::HighQuality,
..Default::default()
}),
interpolation: None,
});
@@ -128,6 +129,7 @@ impl PresetManager {
compression: 0.0,
blend: 0.1,
quality_preset: QualityPreset::HighQuality,
..Default::default()
}),
interpolation: Some(InterpolationParams {
input_fps: 24,

View File

@@ -201,6 +201,7 @@ pub struct OperationMonitor {
operation_type: String,
input_size_mb: f64,
start_time: Instant,
#[allow(dead_code)]
enable_monitoring: bool,
}

View File

@@ -10,14 +10,65 @@ 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<u32>, // 目标宽度
pub target_height: Option<u32>, // 目标高度
pub maintain_aspect: bool, // 保持宽高比
pub pad_color: String, // 填充颜色
// 编码参数
pub codec: Option<String>, // 编码器 (h264_nvenc, hevc_nvenc, libx264等)
pub profile: Option<String>, // 编码配置文件
pub pixel_format: String, // 像素格式
pub gop_size: u32, // GOP大小
pub preset: Option<String>, // 编码预设
pub tune: Option<String>, // 调优选项
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<String>, // 自定义元数据
}
/// Parameters for frame interpolation
@@ -36,6 +87,58 @@ pub struct VideoEnhanceParams {
pub interpolation: Option<InterpolationParams>,
}
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 {
@@ -44,7 +147,12 @@ impl VideoUpscaleParams {
model: UpscaleModel::Thf4,
compression: 0.3,
blend: 0.2,
quality_preset: QualityPreset::HighQuality,
preblur: 0.0,
noise: 20.0,
details: 30.0,
halo: 10.0,
blur: 15.0,
..Default::default()
}
}
@@ -55,10 +163,16 @@ impl VideoUpscaleParams {
model: UpscaleModel::Ghq5,
compression: 0.0,
blend: 0.0,
quality_preset: QualityPreset::HighQuality,
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 {
@@ -66,10 +180,15 @@ impl VideoUpscaleParams {
model: UpscaleModel::Iris3,
compression: -0.1,
blend: 0.1,
quality_preset: QualityPreset::HighQuality,
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 {
@@ -77,7 +196,52 @@ impl VideoUpscaleParams {
model: UpscaleModel::Nyx3,
compression: -0.2,
blend: 0.1,
quality_preset: QualityPreset::HighQuality,
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()
}
}
}
@@ -230,6 +394,7 @@ pub async fn quick_upscale_video(
compression: 0.0,
blend: 0.0,
quality_preset: crate::config::QualityPreset::HighQuality,
..Default::default()
};
// Perform upscaling
@@ -272,6 +437,7 @@ pub async fn auto_enhance_video(
compression: 0.0,
blend: 0.1,
quality_preset: crate::config::QualityPreset::HighQuality,
..Default::default()
});
}

View File

@@ -45,23 +45,24 @@ impl TvaiProcessor {
"-vf", &upscale_filter,
];
// Add encoding settings
let (codec, preset) = params.quality_preset.get_encoding_settings(self.is_gpu_enabled());
let quality = params.quality_preset.get_quality_value(self.is_gpu_enabled());
// 构建所有参数字符串
let mut all_args = Vec::new();
if self.is_gpu_enabled() {
args.extend_from_slice(&[
"-c:v", codec,
"-preset", preset,
"-global_quality", quality,
"-pix_fmt", "yuv420p",
]);
} else {
args.extend_from_slice(&[
"-c:v", codec,
"-preset", preset,
"-crf", quality,
]);
// 添加编码参数
let encoding_args = self.build_encoding_args(&params)?;
all_args.extend(encoding_args);
// 添加音频参数
let audio_args = self.build_audio_args(&params.audio_mode)?;
all_args.extend(audio_args);
// 添加元数据参数
let metadata_args = self.build_metadata_args(&params)?;
all_args.extend(metadata_args);
// 转换为&str并添加到args
for arg in &all_args {
args.push(arg.as_str());
}
args.push(output_path.to_str().unwrap());
@@ -104,9 +105,10 @@ impl TvaiProcessor {
/// Validate upscaling parameters
fn validate_upscale_params(&self, params: &VideoUpscaleParams) -> Result<(), TvaiError> {
if params.scale_factor < 1.0 || params.scale_factor > 4.0 {
// 验证基础参数
if params.scale_factor < 0.0 || params.scale_factor > 4.0 {
return Err(TvaiError::InvalidParameter(
format!("Scale factor must be between 1.0 and 4.0, got {}", params.scale_factor)
format!("Scale factor must be between 0.0 and 4.0, got {}", params.scale_factor)
));
}
@@ -122,9 +124,65 @@ impl TvaiProcessor {
));
}
// 验证TVAI参数
if params.preblur < 0.0 || params.preblur > 100.0 {
return Err(TvaiError::InvalidParameter(
format!("Preblur must be between 0.0 and 100.0, got {}", params.preblur)
));
}
if params.noise < 0.0 || params.noise > 100.0 {
return Err(TvaiError::InvalidParameter(
format!("Noise must be between 0.0 and 100.0, got {}", params.noise)
));
}
if params.details < 0.0 || params.details > 100.0 {
return Err(TvaiError::InvalidParameter(
format!("Details must be between 0.0 and 100.0, got {}", params.details)
));
}
if params.halo < 0.0 || params.halo > 100.0 {
return Err(TvaiError::InvalidParameter(
format!("Halo must be between 0.0 and 100.0, got {}", params.halo)
));
}
if params.blur < 0.0 || params.blur > 100.0 {
return Err(TvaiError::InvalidParameter(
format!("Blur must be between 0.0 and 100.0, got {}", params.blur)
));
}
if params.estimate < 1 || params.estimate > 20 {
return Err(TvaiError::InvalidParameter(
format!("Estimate must be between 1 and 20, got {}", params.estimate)
));
}
if params.instances < 1 || params.instances > 4 {
return Err(TvaiError::InvalidParameter(
format!("Instances must be between 1 and 4, got {}", params.instances)
));
}
// 验证编码参数
if params.quality_param > 51 {
return Err(TvaiError::InvalidParameter(
format!("Quality parameter must be <= 51, got {}", params.quality_param)
));
}
if params.aq_strength > 15 {
return Err(TvaiError::InvalidParameter(
format!("AQ strength must be <= 15, got {}", params.aq_strength)
));
}
// Check if model forces a specific scale
if let Some(forced_scale) = params.model.forces_scale() {
if (params.scale_factor - forced_scale).abs() > 0.01 {
if params.scale_factor > 0.0 && (params.scale_factor - forced_scale).abs() > 0.01 {
return Err(TvaiError::InvalidParameter(
format!("Model {} forces scale factor {}, but {} was requested",
params.model.as_str(), forced_scale, params.scale_factor)
@@ -137,14 +195,185 @@ impl TvaiProcessor {
/// Build Topaz upscaling filter string
fn build_upscale_filter(&self, params: &VideoUpscaleParams) -> Result<String, TvaiError> {
let filter = format!(
"tvai_up=model={}:scale={}:estimate=8:compression={}:blend={}",
params.model.as_str(),
params.scale_factor,
params.compression,
params.blend
);
let mut filter_parts = Vec::new();
Ok(filter)
// 构建TVAI upscale滤镜
let mut tvai_params = vec![
format!("model={}", params.model.as_str()),
format!("scale={}", if params.scale_factor == 0.0 { 0 } else { params.scale_factor as u32 }),
format!("preblur={}", params.preblur),
format!("noise={}", params.noise),
format!("details={}", params.details),
format!("halo={}", params.halo),
format!("blur={}", params.blur),
format!("compression={}", params.compression),
format!("estimate={}", params.estimate),
format!("blend={}", params.blend),
format!("device={}", params.device),
format!("vram={}", params.vram),
format!("instances={}", params.instances),
];
// 如果指定了目标尺寸,添加宽高参数
if let (Some(width), Some(height)) = (params.target_width, params.target_height) {
tvai_params.push(format!("w={}", width));
tvai_params.push(format!("h={}", height));
}
let tvai_filter = format!("tvai_up={}", tvai_params.join(":"));
filter_parts.push(tvai_filter);
// 如果需要额外的缩放和填充
if let (Some(width), Some(height)) = (params.target_width, params.target_height) {
if params.maintain_aspect {
// 添加缩放滤镜保持宽高比
let scale_filter = format!(
"scale=w={}:h={}:flags=lanczos:threads=0:force_original_aspect_ratio=decrease",
width, height
);
filter_parts.push(scale_filter);
// 添加填充滤镜
let pad_filter = format!(
"pad={}:{}:-1:-1:color={}",
width, height, params.pad_color
);
filter_parts.push(pad_filter);
}
}
Ok(filter_parts.join(","))
}
/// Build encoding arguments
fn build_encoding_args(&self, params: &VideoUpscaleParams) -> Result<Vec<String>, TvaiError> {
let mut args = Vec::new();
// 确定编码器
let codec = params.codec.as_deref().unwrap_or_else(|| {
if self.is_gpu_enabled() {
"h264_nvenc"
} else {
"libx264"
}
});
args.extend_from_slice(&["-c:v".to_string(), codec.to_string()]);
// 添加编码配置文件
if let Some(profile) = &params.profile {
args.extend_from_slice(&["-profile:v".to_string(), profile.clone()]);
}
// 添加像素格式
args.extend_from_slice(&["-pix_fmt".to_string(), params.pixel_format.clone()]);
// 添加GOP大小
args.extend_from_slice(&["-g".to_string(), params.gop_size.to_string()]);
if codec.contains("nvenc") {
// NVIDIA GPU编码器参数
if let Some(preset) = &params.preset {
args.extend_from_slice(&["-preset".to_string(), preset.clone()]);
}
if let Some(tune) = &params.tune {
args.extend_from_slice(&["-tune".to_string(), tune.clone()]);
}
args.extend_from_slice(&["-rc".to_string(), params.rate_control.clone()]);
args.extend_from_slice(&["-qp".to_string(), params.quality_param.to_string()]);
args.extend_from_slice(&["-rc-lookahead".to_string(), params.lookahead.to_string()]);
if params.spatial_aq {
args.extend_from_slice(&["-spatial_aq".to_string(), "1".to_string()]);
args.extend_from_slice(&["-aq-strength".to_string(), params.aq_strength.to_string()]);
}
if params.bitrate > 0 {
args.extend_from_slice(&["-b:v".to_string(), params.bitrate.to_string()]);
} else {
args.extend_from_slice(&["-b:v".to_string(), "0".to_string()]);
}
if params.buffer_frames > 0 {
args.extend_from_slice(&["-bf".to_string(), params.buffer_frames.to_string()]);
} else {
args.extend_from_slice(&["-bf".to_string(), "0".to_string()]);
}
} else {
// CPU编码器参数
if let Some(preset) = &params.preset {
args.extend_from_slice(&["-preset".to_string(), preset.clone()]);
}
if let Some(tune) = &params.tune {
args.extend_from_slice(&["-tune".to_string(), tune.clone()]);
}
args.extend_from_slice(&["-crf".to_string(), params.quality_param.to_string()]);
}
// 添加帧率模式
args.extend_from_slice(&["-fps_mode:v".to_string(), "passthrough".to_string()]);
// 添加MOV标志
args.extend_from_slice(&[
"-movflags".to_string(),
"frag_keyframe+empty_moov+delay_moov+use_metadata_tags+write_colr".to_string()
]);
Ok(args)
}
/// Build audio arguments
fn build_audio_args(&self, audio_mode: &crate::video::AudioMode) -> Result<Vec<String>, TvaiError> {
let mut args = Vec::new();
match audio_mode {
crate::video::AudioMode::Keep => {
// 保留音频,复制流
args.extend_from_slice(&["-c:a".to_string(), "copy".to_string()]);
}
crate::video::AudioMode::Remove => {
// 移除音频
args.push("-an".to_string());
}
crate::video::AudioMode::Reencode { codec, bitrate } => {
// 重新编码音频
args.extend_from_slice(&["-c:a".to_string(), codec.clone()]);
args.extend_from_slice(&["-b:a".to_string(), format!("{}k", bitrate)]);
}
}
Ok(args)
}
/// Build metadata arguments
fn build_metadata_args(&self, params: &VideoUpscaleParams) -> Result<Vec<String>, TvaiError> {
let mut args = Vec::new();
if params.preserve_metadata {
args.extend_from_slice(&["-map_metadata".to_string(), "0".to_string()]);
args.extend_from_slice(&["-map_metadata:s:v".to_string(), "0:s:v".to_string()]);
}
// 添加自定义元数据
if let Some(custom_metadata) = &params.custom_metadata {
args.extend_from_slice(&["-metadata".to_string(), custom_metadata.clone()]);
} else {
// 添加默认的VideoAI元数据
let metadata = format!(
"videoai=Enhanced using {}; mode: auto; revert compression at {}; recover details at {}; sharpen at {}; reduce noise at {}; dehalo at {}; anti-alias/deblur at {}; focus fix Off; and recover original detail at {}. Changed resolution to {}x{}",
params.model.as_str(),
params.compression,
params.details,
params.blur,
params.noise,
params.halo,
params.blur,
params.blend * 100.0,
params.target_width.unwrap_or(0),
params.target_height.unwrap_or(0)
);
args.extend_from_slice(&["-metadata".to_string(), metadata]);
}
Ok(args)
}
}