From 44f0b399ec9a8f06fb348b4cb53d06cb506a6421 Mon Sep 17 00:00:00 2001 From: imeepos Date: Mon, 18 Aug 2025 16:06:15 +0800 Subject: [PATCH] feat: fix ffmpeg bug --- .../components/TopazVideoAIConfigurator.tsx | 974 ++++-------------- cargos/tvai/src/config/topaz_templates.rs | 178 ++++ cargos/tvai/src/web_api.rs | 4 +- 3 files changed, 371 insertions(+), 785 deletions(-) diff --git a/apps/desktop/src/components/TopazVideoAIConfigurator.tsx b/apps/desktop/src/components/TopazVideoAIConfigurator.tsx index 0440c30..d02b0c0 100644 --- a/apps/desktop/src/components/TopazVideoAIConfigurator.tsx +++ b/apps/desktop/src/components/TopazVideoAIConfigurator.tsx @@ -8,14 +8,6 @@ import { Sparkles, FolderOpen, FileVideo, - Wand2, - Gauge, - Maximize, - RotateCcw, - Eye, - Sun, - ChevronDown, - ChevronRight, RefreshCw } from 'lucide-react'; import { useNavigate } from 'react-router-dom'; @@ -116,23 +108,22 @@ interface TopazSettings { const TopazVideoAIConfigurator: React.FC = () => { const navigate = useNavigate(); - + // 基础状态 const [currentTemplate, setCurrentTemplate] = useState(null); const [templates, setTemplates] = useState>({}); const [templatesLoading, setTemplatesLoading] = useState(true); - + // 文件设置 const [inputFile, setInputFile] = useState(''); const [outputFolder, setOutputFolder] = useState(''); const [outputFilename, setOutputFilename] = useState('enhanced_video.mp4'); - + // 处理设置 const [processingMode, setProcessingMode] = useState('single'); const [rateControl, setRateControl] = useState('constqp'); - + // UI 状态 - const [activeSection, setActiveSection] = useState('files'); const [expandedSections, setExpandedSections] = useState>(new Set(['files'])); const [generatedCommand, setGeneratedCommand] = useState(''); const [showToast, setShowToast] = useState(false); @@ -500,808 +491,223 @@ const TopazVideoAIConfigurator: React.FC = () => { {/* 主要内容 */}
-
- {/* 左侧:模板和文件设置 */} -
- {/* 模板选择 */} -
-
-

- - 内置模板 ({templatesLoading ? '加载中...' : Object.keys(templates).length}) -

+
+ {/* 内置模板 - 平铺卡片布局 */} +
+
+

+ + 内置模板 ({templatesLoading ? '加载中...' : Object.keys(templates).length}) +

- {templatesLoading ? ( -
- - 加载模板中... -
- ) : ( -
- {Object.entries(templates).map(([key, template]) => ( -
selectTemplate(key)} - > -
- {template.icon || '📄'} -
-

{template.name}

-

{template.description}

-
-
-
- ))} -
- )} -
-
- - {/* 文件设置 */} -
-
-

- - 文件设置 -

- -
-
- -
-
- setInputFile(e.target.value)} - placeholder="选择输入视频文件..." - className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" - title={inputFile} // 显示完整路径的提示 - /> - {inputFile && ( -
- {getFileName(inputFile)} -
- )} -
- -
-
- -
- -
-
- setOutputFolder(e.target.value)} - placeholder="选择输出文件夹..." - className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" - title={outputFolder} // 显示完整路径的提示 - /> - {outputFolder && ( -
- 📁 {outputFolder} -
- )} -
- -
-
- -
- - setOutputFilename(e.target.value)} - placeholder="enhanced_video.mp4" - className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" - /> -
+ {templatesLoading ? ( +
+ + 加载模板中...
-
+ ) : ( +
+ {Object.entries(templates).map(([key, template]) => ( +
selectTemplate(key)} + > + {/* 选中指示器 */} + {currentTemplate === key && ( +
+ + + +
+ )} + +
+
{template.icon || '📄'}
+

{template.name}

+

{template.description}

+
+ + {/* 悬停效果 */} +
+
+ ))} +
+ )}
- {/* 中间:参数配置 */} -
- {/* 处理模式设置 */} -
-
-

- - 处理模式 -

+
+ {/* 左侧:文件设置 */} +
-
-
- - -
- -
- - -
-
-
-
- - {/* 防抖设置 */} -
-
-
toggleSection('stabilize')} - > -

- - 防抖设置 + {/* 文件设置 */} +
+
+

+ + 文件设置

-
- - {expandedSections.has('stabilize') ? - : - - } -
-
- {expandedSections.has('stabilize') && settings.stabilize.active && ( -
+
- - updateSetting('stabilize', 'smooth', parseInt(e.target.value))} - className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" - /> -
- -
- - -
- -
- - updateSetting('stabilize', 'reduce_motion_iteration', parseInt(e.target.value))} - className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" - /> -
- -
- -
-
- )} -
-
- - {/* 运动模糊去除设置 */} -
-
-
toggleSection('motionblur')} - > -

- - 运动模糊去除 -

-
- - {expandedSections.has('motionblur') ? - : - - } -
-
- - {expandedSections.has('motionblur') && settings.motionblur.active && ( -
-
- - -
-
- )} -
-
- - {/* 慢动作设置 */} -
-
-
toggleSection('slowmo')} - > -

- - 慢动作/插帧 -

-
- - {expandedSections.has('slowmo') ? - : - - } -
-
- - {expandedSections.has('slowmo') && settings.slowmo.active && ( -
-
- - -
- -
- - -
- -
- - updateSetting('slowmo', 'duplicate_threshold', parseInt(e.target.value))} - className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" - /> -
- -
- -
-
- )} -
-
- {/* AI 增强设置 */} -
-
-
toggleSection('enhance')} - > -

- - AI 增强设置 -

-
- - {expandedSections.has('enhance') ? - : - - } -
-
- - {expandedSections.has('enhance') && settings.enhance.active && ( -
-
-
- - -
- -
- - -
-
- -
-
- - updateSetting('enhance', 'detail', parseInt(e.target.value))} - className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" - /> -
- -
- - updateSetting('enhance', 'sharpen', parseInt(e.target.value))} - className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" - /> -
- -
- - updateSetting('enhance', 'denoise', parseInt(e.target.value))} - className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" - /> -
- -
- - updateSetting('enhance', 'deblur', parseInt(e.target.value))} - className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" - /> -
-
- -
-
- - updateSetting('enhance', 'dehalo', parseInt(e.target.value))} - className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" - /> -
- -
- - updateSetting('enhance', 'compress', parseInt(e.target.value))} - className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" - /> -
- -
- - updateSetting('enhance', 'recover_original_detail_value', parseInt(e.target.value))} - className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" - /> -
-
-
- )} -
-
- - {/* 输出设置 */} -
-
-
toggleSection('output')} - > -

- - 输出设置 -

-
- - {expandedSections.has('output') ? - : - - } -
-
- - {expandedSections.has('output') && settings.output.active && ( -
-
- - -
- -
- - updateSetting('output', 'out_fps', parseInt(e.target.value))} - className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" - /> -
- -
- -
- -
- -
-
- )} -
-
- - {/* HDR 设置 */} -
-
-
toggleSection('hdr')} - > -

- - HDR 处理 -

-
- - {expandedSections.has('hdr') ? - : - - } -
-
- - {expandedSections.has('hdr') && settings.hdr?.active && ( -
-
- - -
- -
- - -
- -
- - updateSetting('hdr', 'auto', parseInt(e.target.value))} - className="w-full" - /> -
{settings.hdr?.auto || 0}
-
- -
- - updateSetting('hdr', 'exposure', parseInt(e.target.value))} - className="w-full" - /> -
{settings.hdr?.exposure || 0}
-
- -
- - updateSetting('hdr', 'saturation', parseInt(e.target.value))} - className="w-full" - /> -
{settings.hdr?.saturation || 0}
-
- -
- - updateSetting('hdr', 'sdr_inflection_point', parseInt(e.target.value) / 100)} - className="w-full" - /> -
{(settings.hdr?.sdr_inflection_point || 0.7).toFixed(2)}
-
-
- )} -
-
- - {/* 视频处理 */} -
-
-

- - 视频处理 -

- -
- {!isProcessing ? ( -
- - +
+
+ setInputFile(e.target.value)} + placeholder="选择输入视频文件..." + className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" + title={inputFile} // 显示完整路径的提示 + /> + {inputFile && ( +
+ {getFileName(inputFile)} +
+ )} +
- {generatedCommand && ( +
+
+ +
+ +
+
+ setOutputFolder(e.target.value)} + placeholder="选择输出文件夹..." + className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" + title={outputFolder} // 显示完整路径的提示 + /> + {outputFolder && ( +
+ 📁 {outputFolder} +
+ )} +
+ +
+
+ +
+ + setOutputFilename(e.target.value)} + placeholder="enhanced_video.mp4" + className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent" + /> +
+
+
+
+

+ + {/* 中间:参数配置 */} +
+
+
+

+ + 视频处理 +

+ +
+ {!isProcessing ? ( +
+ + +
- )} -
-
- ) : ( -
-
-
-
- {processingStatus} + {generatedCommand && ( + + )}
+ ) : ( +
+
+
+
+ {processingStatus} +
+
-
-
-
+
+
+
-
- {processingProgress}% 完成 +
+ {processingProgress}% 完成 +
-
- )} + )} - {processingError && ( -
-
-
处理失败
+ {processingError && ( +
+
+
处理失败
+
+
{processingError}
-
{processingError}
-
- )} + )} - {generatedCommand && !isProcessing && ( -
-
生成的命令预览:
-
- {generatedCommand} + {generatedCommand && !isProcessing && ( +
+
生成的命令预览:
+
+ {generatedCommand} +
-
- )} + )} +
- - {/* Toast 通知 */} {showToast && (
{toastMessage} diff --git a/cargos/tvai/src/config/topaz_templates.rs b/cargos/tvai/src/config/topaz_templates.rs index 1c7407a..6dc5b97 100644 --- a/cargos/tvai/src/config/topaz_templates.rs +++ b/cargos/tvai/src/config/topaz_templates.rs @@ -1704,6 +1704,30 @@ impl TopazTemplateManager { format!("tvai_up=model={}:scale=0", model) }; + // Add specific resolution for aspect ratio conversion + println!("Debug: Checking aspect ratio conversion conditions:"); + println!("Debug: template.name = '{}'", template.name); + println!("Debug: template.settings.output.out_size_method = {}", template.settings.output.out_size_method); + println!("Debug: template.settings.output.lock_aspect_ratio = {:?}", template.settings.output.lock_aspect_ratio); + + if template.settings.output.out_size_method == 7 && !template.settings.output.lock_aspect_ratio.unwrap_or(true) { + println!("Debug: Aspect ratio conversion conditions met!"); + // For aspect ratio conversion templates, add specific resolution + if template.name.contains("16:9转9:16") { + // Convert 16:9 to 9:16 - typical mobile format + println!("Debug: Adding 16:9 to 9:16 conversion parameters"); + tvai_filter.push_str(":w=1080:h=1920"); + } else if template.name.contains("9:16转16:9") { + // Convert 9:16 to 16:9 - typical desktop format + println!("Debug: Adding 9:16 to 16:9 conversion parameters"); + tvai_filter.push_str(":w=1920:h=1080"); + } else { + println!("Debug: Template name doesn't match aspect ratio patterns"); + } + } else { + println!("Debug: Aspect ratio conversion conditions NOT met"); + } + // Add blend ratio if let Some(blend) = opts.blend_ratio { tvai_filter.push_str(&format!(":blend={}", blend)); @@ -2161,6 +2185,8 @@ impl BuiltinTemplates { templates.insert("minidv_hd_int_basic".to_string(), Self::minidv_hd_int_basic()); templates.insert("upscale_to_fhd".to_string(), Self::upscale_to_fhd()); templates.insert("upscale_4k_convert_60fps".to_string(), Self::upscale_4k_convert_60fps()); + templates.insert("aspect_ratio_16_9_to_9_16".to_string(), Self::aspect_ratio_16_9_to_9_16()); + templates.insert("aspect_ratio_9_16_to_16_9".to_string(), Self::aspect_ratio_9_16_to_16_9()); templates } @@ -2554,6 +2580,158 @@ impl BuiltinTemplates { template.settings.output.out_fps = 60; template } + + /// 16:9 转 9:16 宽高比转换模板 + pub fn aspect_ratio_16_9_to_9_16() -> TopazTemplate { + TopazTemplate { + name: "16:9转9:16".to_string(), + description: "将16:9横屏视频转换为9:16竖屏格式,适用于短视频平台".to_string(), + author: "Topaz Video AI".to_string(), + save_output_settings: false, + date: "2025-08-18".to_string(), + veaiversion: "5.0.0".to_string(), + editable: true, + enabled: true, + path: None, + settings: TopazSettings { + stabilize: StabilizeSettings { + active: false, + smooth: 50, + method: 1, // 无裁剪 + rsc: false, + reduce_motion: false, + reduce_motion_iteration: 2, + }, + motionblur: MotionBlurSettings { + active: false, + model: "thm-2".to_string(), + model_name: Some("thm-2".to_string()), + }, + slowmo: SlowMotionSettings { + active: false, + model: "apo-8".to_string(), + factor: 1, + duplicate: false, + duplicate_threshold: 10, + }, + enhance: EnhanceSettings { + active: true, + model: "prob-4".to_string(), // 高质量增强模型 + video_type: 1, // 逐行扫描 + auto: 0, + field_order: 0, + compress: 0, + detail: 0, + sharpen: 0, + denoise: 0, + dehalo: 0, + deblur: 0, + add_noise: 0, + recover_original_detail_value: 20, + focus_fix_level: Some("Standard".to_string()), + is_artemis: false, + is_gaia: false, + is_theia: false, + is_proteus: false, + is_iris: false, + is_second_enhancement: Some(false), + }, + grain: GrainSettings { + active: false, + grain: 0, + grain_size: 2, + }, + output: OutputSettings { + active: true, + out_size_method: 7, // 自定义尺寸 + crop_to_fit: true, // 裁剪适应 + output_par: 0, + out_fps: 0, // 保持原始帧率 + custom_resolution_priority: Some(2), + lock_aspect_ratio: Some(false), // 允许改变宽高比 + }, + hdr: None, + second_enhance: None, + filter_manager: None, + }, + } + } + + /// 9:16 转 16:9 宽高比转换模板 + pub fn aspect_ratio_9_16_to_16_9() -> TopazTemplate { + TopazTemplate { + name: "9:16转16:9".to_string(), + description: "将9:16竖屏视频转换为16:9横屏格式,适用于电视和电脑播放".to_string(), + author: "Topaz Video AI".to_string(), + save_output_settings: false, + date: "2025-08-18".to_string(), + veaiversion: "5.0.0".to_string(), + editable: true, + enabled: true, + path: None, + settings: TopazSettings { + stabilize: StabilizeSettings { + active: false, + smooth: 50, + method: 1, // 无裁剪 + rsc: false, + reduce_motion: false, + reduce_motion_iteration: 2, + }, + motionblur: MotionBlurSettings { + active: false, + model: "thm-2".to_string(), + model_name: Some("thm-2".to_string()), + }, + slowmo: SlowMotionSettings { + active: false, + model: "apo-8".to_string(), + factor: 1, + duplicate: false, + duplicate_threshold: 10, + }, + enhance: EnhanceSettings { + active: true, + model: "prob-4".to_string(), // 高质量增强模型 + video_type: 1, // 逐行扫描 + auto: 0, + field_order: 0, + compress: 0, + detail: 0, + sharpen: 0, + denoise: 0, + dehalo: 0, + deblur: 0, + add_noise: 0, + recover_original_detail_value: 20, + focus_fix_level: Some("Standard".to_string()), + is_artemis: false, + is_gaia: false, + is_theia: false, + is_proteus: false, + is_iris: false, + is_second_enhancement: Some(false), + }, + grain: GrainSettings { + active: false, + grain: 0, + grain_size: 2, + }, + output: OutputSettings { + active: true, + out_size_method: 7, // 自定义尺寸 + crop_to_fit: true, // 裁剪适应 + output_par: 0, + out_fps: 0, // 保持原始帧率 + custom_resolution_priority: Some(2), + lock_aspect_ratio: Some(false), // 允许改变宽高比 + }, + hdr: None, + second_enhance: None, + filter_manager: None, + }, + } + } } // Implement Default for all settings structs diff --git a/cargos/tvai/src/web_api.rs b/cargos/tvai/src/web_api.rs index b66e194..41030aa 100644 --- a/cargos/tvai/src/web_api.rs +++ b/cargos/tvai/src/web_api.rs @@ -157,7 +157,9 @@ impl WebApi { "film_stock_4k_strong", "minidv_hd_int_basic", "upscale_to_fhd", - "upscale_4k_convert_60fps" + "upscale_4k_convert_60fps", + "aspect_ratio_16_9_to_9_16", + "aspect_ratio_9_16_to_16_9" ]; for name in &template_names {