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 1bf9830..4070aa5 100644 --- a/apps/desktop/src-tauri/src/business/services/material_service.rs +++ b/apps/desktop/src-tauri/src/business/services/material_service.rs @@ -416,19 +416,27 @@ impl MaterialService { material: &Material, config: &MaterialProcessingConfig, ) -> Result<()> { - // 根据场景检测结果或固定时长切分 - let segments = if let Some(scene_detection) = &material.scene_detection { - // 使用场景检测结果切分 - Self::create_segments_from_scenes(&scene_detection.scenes, config.max_segment_duration) + // 第一步:根据场景检测结果进行分镜头切分 + let primary_segments = if let Some(scene_detection) = &material.scene_detection { + // 使用场景检测结果,每个场景作为一个片段 + println!("使用场景检测结果进行分镜头切分,共 {} 个场景", scene_detection.scenes.len()); + Self::create_segments_from_scenes_direct(&scene_detection.scenes) } else { - // 使用固定时长切分 + // 没有场景检测结果,使用固定时长切分 if let Some(duration) = material.get_duration() { + println!("没有场景检测结果,使用固定时长切分"); Self::create_fixed_segments(duration, config.max_segment_duration) } else { return Err(anyhow!("无法获取视频时长")); } }; + // 第二步:对超长的分镜头进行二次切分 + let final_segments = Self::apply_duration_limit(&primary_segments, config.max_segment_duration); + + println!("分镜头切分完成:{} 个片段", primary_segments.len()); + println!("二次切分后:{} 个片段", final_segments.len()); + // 创建输出目录 let output_dir = format!("{}_segments", material.original_path.trim_end_matches(".mp4")); @@ -439,7 +447,7 @@ impl MaterialService { FFmpegService::split_video_fast( &material.original_path, &output_dir, - &segments, + &final_segments, &material.name.replace(".mp4", ""), )? } @@ -448,7 +456,7 @@ impl MaterialService { FFmpegService::split_video( &material.original_path, &output_dir, - &segments, + &final_segments, &material.name.replace(".mp4", ""), )? } @@ -457,7 +465,7 @@ impl MaterialService { FFmpegService::split_video_smart( &material.original_path, &output_dir, - &segments, + &final_segments, &material.name.replace(".mp4", ""), )? } @@ -465,7 +473,7 @@ impl MaterialService { // 保存片段信息到数据库 for (index, output_file) in output_files.iter().enumerate() { - let (start_time, end_time) = segments[index]; + let (start_time, end_time) = final_segments[index]; let file_size = std::fs::metadata(output_file)?.len(); let segment = crate::data::models::material::MaterialSegment::new( @@ -483,66 +491,70 @@ impl MaterialService { Ok(()) } - /// 根据场景创建切分片段 + /// 直接根据场景创建分镜头片段(第一次切分) + pub fn create_segments_from_scenes_direct( + scenes: &[crate::data::models::material::SceneSegment], + ) -> Vec<(f64, f64)> { + let mut segments = Vec::new(); + + for scene in scenes { + segments.push((scene.start_time, scene.end_time)); + } + + println!("分镜头切分:根据 {} 个场景创建 {} 个片段", scenes.len(), segments.len()); + for (i, (start, end)) in segments.iter().enumerate() { + println!(" 分镜头 {}: {:.2}s - {:.2}s (时长: {:.2}s)", + i + 1, start, end, end - start); + } + + segments + } + + /// 对片段应用时长限制(二次切分) + pub fn apply_duration_limit( + segments: &[(f64, f64)], + max_duration: f64, + ) -> Vec<(f64, f64)> { + let mut final_segments = Vec::new(); + + println!("开始二次切分,最大时长限制: {}秒", max_duration); + + for (i, (start, end)) in segments.iter().enumerate() { + let duration = end - start; + + if duration > max_duration { + println!(" 分镜头 {} 超长 ({:.2}s > {:.2}s),进行二次切分", + i + 1, duration, max_duration); + + // 将超长片段按最大时长切分 + let sub_segments = Self::create_fixed_segments_range(*start, *end, max_duration); + + println!(" 切分为 {} 个子片段:", sub_segments.len()); + for (j, (sub_start, sub_end)) in sub_segments.iter().enumerate() { + println!(" 子片段 {}: {:.2}s - {:.2}s (时长: {:.2}s)", + j + 1, sub_start, sub_end, sub_end - sub_start); + } + + final_segments.extend(sub_segments); + } else { + println!(" 分镜头 {} 时长合适 ({:.2}s ≤ {:.2}s),保持不变", + i + 1, duration, max_duration); + final_segments.push((*start, *end)); + } + } + + println!("二次切分完成,最终 {} 个片段", final_segments.len()); + final_segments + } + + /// 根据场景创建切分片段(旧版本,保留兼容性) pub fn create_segments_from_scenes( scenes: &[crate::data::models::material::SceneSegment], max_duration: f64, ) -> Vec<(f64, f64)> { - let mut segments = Vec::new(); - let mut current_start = 0.0; - let mut current_end = 0.0; - - println!("开始根据场景创建切分片段,最大时长: {}秒", max_duration); - - for (i, scene) in scenes.iter().enumerate() { - let potential_end = scene.end_time; - let potential_duration = potential_end - current_start; - - println!(" 处理场景 {}: {:.2}s - {:.2}s (时长: {:.2}s)", - i + 1, scene.start_time, scene.end_time, scene.duration); - - if potential_duration > max_duration && current_end > current_start { - // 当前片段已达到最大时长,创建新片段 - segments.push((current_start, current_end)); - println!(" 创建片段: {:.2}s - {:.2}s (时长: {:.2}s)", - current_start, current_end, current_end - current_start); - - current_start = current_end; - current_end = scene.end_time; - } else { - // 继续扩展当前片段 - current_end = scene.end_time; - } - } - - // 添加最后一个片段 - if current_end > current_start { - segments.push((current_start, current_end)); - println!(" 创建最后片段: {:.2}s - {:.2}s (时长: {:.2}s)", - current_start, current_end, current_end - current_start); - } - - // 对超长片段进行二次切分 - let mut final_segments = Vec::new(); - for (start, end) in segments { - let duration = end - start; - if duration > max_duration { - println!(" 片段过长 ({:.2}s > {:.2}s),进行二次切分", duration, max_duration); - // 将超长片段按最大时长切分 - let sub_segments = Self::create_fixed_segments_range(start, end, max_duration); - final_segments.extend(sub_segments); - } else { - final_segments.push((start, end)); - } - } - - println!("最终生成 {} 个切分片段:", final_segments.len()); - for (i, (start, end)) in final_segments.iter().enumerate() { - println!(" 片段 {}: {:.2}s - {:.2}s (时长: {:.2}s)", - i + 1, start, end, end - start); - } - - final_segments + // 使用新的两步法 + let primary_segments = Self::create_segments_from_scenes_direct(scenes); + Self::apply_duration_limit(&primary_segments, max_duration) } /// 创建固定时长的切分片段