diff --git a/apps/desktop/src-tauri/src/business/services/async_material_service.rs b/apps/desktop/src-tauri/src/business/services/async_material_service.rs
index f761493..95ebefa 100644
--- a/apps/desktop/src-tauri/src/business/services/async_material_service.rs
+++ b/apps/desktop/src-tauri/src/business/services/async_material_service.rs
@@ -306,9 +306,61 @@ impl AsyncMaterialService {
let original_path = material.original_path.clone();
let threshold = config.scene_detection_threshold;
-
+ let skip_start_ms = config.skip_start_ms;
+
match task::spawn_blocking(move || {
- MaterialService::detect_video_scenes(&original_path, threshold)
+ // 如果设置了跳过开头,先创建临时视频文件
+ let detection_file_path = if let Some(skip_ms) = skip_start_ms {
+ if skip_ms > 0 {
+ println!("异步处理 - AI生成视频前置跳过: {}ms", skip_ms);
+ match crate::infrastructure::ffmpeg::FFmpegService::create_trimmed_video(&original_path, skip_ms) {
+ Ok(temp_path) => {
+ println!("异步处理 - 临时视频创建成功: {}", temp_path);
+ temp_path
+ }
+ Err(e) => {
+ eprintln!("异步处理 - 创建临时视频失败,使用原视频: {}", e);
+ original_path.clone()
+ }
+ }
+ } else {
+ original_path.clone()
+ }
+ } else {
+ original_path.clone()
+ };
+
+ let result = MaterialService::detect_video_scenes(&detection_file_path, threshold);
+
+ // 处理结果并调整时间戳
+ let final_result = match result {
+ Ok(mut scene_detection) => {
+ // 如果使用了临时文件,需要调整场景时间戳
+ if let Some(skip_ms) = skip_start_ms {
+ if skip_ms > 0 && detection_file_path != original_path {
+ let skip_seconds = skip_ms as f64 / 1000.0;
+ println!("异步处理 - 调整场景时间戳,补偿跳过的{}秒", skip_seconds);
+ for scene in &mut scene_detection.scenes {
+ scene.start_time += skip_seconds;
+ scene.end_time += skip_seconds;
+ }
+ }
+ }
+ Ok(scene_detection)
+ }
+ Err(e) => Err(e),
+ };
+
+ // 清理临时文件
+ if detection_file_path != original_path {
+ if let Err(e) = std::fs::remove_file(&detection_file_path) {
+ eprintln!("异步处理 - 清理临时文件失败: {}", e);
+ } else {
+ println!("异步处理 - 临时文件清理成功: {}", detection_file_path);
+ }
+ }
+
+ final_result
}).await? {
Ok(scene_detection) => {
info!("异步场景检测成功,发现 {} 个场景", scene_detection.scenes.len());
diff --git a/apps/desktop/src-tauri/src/business/services/material_service.rs b/apps/desktop/src-tauri/src/business/services/material_service.rs
index 2f19584..8286339 100644
--- a/apps/desktop/src-tauri/src/business/services/material_service.rs
+++ b/apps/desktop/src-tauri/src/business/services/material_service.rs
@@ -344,15 +344,65 @@ impl MaterialService {
// 2. 场景检测(如果是视频且启用了场景检测)
if matches!(material.material_type, MaterialType::Video) && config.enable_scene_detection {
println!("开始视频场景检测: {}", material.original_path);
- match Self::detect_video_scenes(&material.original_path, config.scene_detection_threshold) {
- Ok(scene_detection) => {
+
+ // 如果设置了跳过开头,先创建临时视频文件
+ let detection_file_path = if let Some(skip_ms) = config.skip_start_ms {
+ if skip_ms > 0 {
+ println!("AI生成视频前置跳过: {}ms", skip_ms);
+ match crate::infrastructure::ffmpeg::FFmpegService::create_trimmed_video(&material.original_path, skip_ms) {
+ Ok(temp_path) => {
+ println!("临时视频创建成功,用于场景检测: {}", temp_path);
+ temp_path
+ }
+ Err(e) => {
+ eprintln!("创建临时视频失败,使用原视频: {}", e);
+ material.original_path.clone()
+ }
+ }
+ } else {
+ material.original_path.clone()
+ }
+ } else {
+ material.original_path.clone()
+ };
+
+ match Self::detect_video_scenes(&detection_file_path, config.scene_detection_threshold) {
+ Ok(mut scene_detection) => {
+ // 如果使用了临时文件,需要调整场景时间戳
+ if let Some(skip_ms) = config.skip_start_ms {
+ if skip_ms > 0 && detection_file_path != material.original_path {
+ let skip_seconds = skip_ms as f64 / 1000.0;
+ println!("调整场景时间戳,补偿跳过的{}秒", skip_seconds);
+ for scene in &mut scene_detection.scenes {
+ scene.start_time += skip_seconds;
+ scene.end_time += skip_seconds;
+ }
+ }
+ }
+
println!("场景检测成功,发现 {} 个场景", scene_detection.scenes.len());
material.set_scene_detection(scene_detection);
repository.update(&material)?;
+
+ // 清理临时文件
+ if detection_file_path != material.original_path {
+ if let Err(e) = std::fs::remove_file(&detection_file_path) {
+ eprintln!("清理临时文件失败: {}", e);
+ } else {
+ println!("临时文件清理成功: {}", detection_file_path);
+ }
+ }
}
Err(e) => {
// 场景检测失败不应该导致整个处理失败
eprintln!("场景检测失败: {}", e);
+
+ // 清理临时文件
+ if detection_file_path != material.original_path {
+ if let Err(e) = std::fs::remove_file(&detection_file_path) {
+ eprintln!("清理临时文件失败: {}", e);
+ }
+ }
}
}
} else {
diff --git a/apps/desktop/src-tauri/src/data/models/material.rs b/apps/desktop/src-tauri/src/data/models/material.rs
index 5ae0eff..f019ab0 100644
--- a/apps/desktop/src-tauri/src/data/models/material.rs
+++ b/apps/desktop/src-tauri/src/data/models/material.rs
@@ -147,6 +147,7 @@ pub struct CreateMaterialRequest {
pub auto_process: bool,
pub max_segment_duration: Option
+ AI生成的视频通常前几帧相同,设置跳过毫秒数可避免切片后首帧重复问题 +
+