diff --git a/python_core/cli/commands/scene_detect.py b/python_core/cli/commands/scene_detect.py index d9092ed..e5e89c0 100644 --- a/python_core/cli/commands/scene_detect.py +++ b/python_core/cli/commands/scene_detect.py @@ -111,6 +111,7 @@ def batch_detect_and_split( use_advanced_split: bool = typer.Option(True, "--advanced/--traditional", help="使用高效批量切分/传统逐个切分"), split_quality: int = typer.Option(23, "--quality", "-q", help="切分质量 (CRF值, 18-28)"), split_preset: str = typer.Option("fast", "--preset", help="编码预设 (ultrafast/fast/medium/slow)"), + max_duration: float = typer.Option(2.0, "--max-duration", "-d", help="最大视频时长限制(秒),超过将二次切分"), verbose: bool = typer.Option(False, "--verbose", "-v", help="详细输出") ): """批量场景检测和视频切分""" @@ -162,7 +163,8 @@ def batch_detect_and_split( continue_on_error=continue_on_error, use_advanced_split=use_advanced_split, split_quality=split_quality, - split_preset=split_preset + split_preset=split_preset, + max_video_duration=max_duration ) # 显示结果 diff --git a/python_core/scene_detection/scene_detector.py b/python_core/scene_detection/scene_detector.py index a4a6314..97528db 100644 --- a/python_core/scene_detection/scene_detector.py +++ b/python_core/scene_detection/scene_detector.py @@ -120,11 +120,12 @@ class SceneDetector: enable_ai_analysis: bool = False, enable_video_splitting: bool = True, max_concurrent: int = 2, continue_on_error: bool = True, use_advanced_split: bool = True, split_quality: int = 23, split_preset: str = "fast", - request_id: Optional[str] = None) -> Dict[str, Any]: + max_video_duration: float = 60.0, request_id: Optional[str] = None) -> Dict[str, Any]: """批量场景检测和视频切分""" return self.workflow_manager.batch_detect_and_split( video_paths, output_base_dir, detector_type, threshold, min_scene_length, output_format, enable_ai_analysis, enable_video_splitting, - max_concurrent, continue_on_error, use_advanced_split, split_quality, split_preset, request_id + max_concurrent, continue_on_error, use_advanced_split, split_quality, split_preset, + max_video_duration, request_id ) diff --git a/python_core/scene_detection/types/batch_workflow_state.py b/python_core/scene_detection/types/batch_workflow_state.py index 9a1de7b..ecc0adc 100644 --- a/python_core/scene_detection/types/batch_workflow_state.py +++ b/python_core/scene_detection/types/batch_workflow_state.py @@ -41,7 +41,7 @@ class BatchSceneDetectionWorkflowState: use_advanced_split: bool = True split_quality: int = 23 split_preset: str = "fast" - max_video_duration: float = 60.0 # 最大视频时长(秒),默认60秒 + max_video_duration: float = 2.0 # 最大视频时长(秒),默认60秒 # 批量处理配置 max_concurrent: int = 4 diff --git a/python_core/scene_detection/workflows/batch_workflow_nodes.py b/python_core/scene_detection/workflows/batch_workflow_nodes.py index 064d675..459be2b 100644 --- a/python_core/scene_detection/workflows/batch_workflow_nodes.py +++ b/python_core/scene_detection/workflows/batch_workflow_nodes.py @@ -296,20 +296,6 @@ class BatchWorkflowNodes: ) split_results_raw.append(split_result) - # 转换为字典格式 - split_results = [ - { - "scene_index": r.scene_index + 1, - "output_path": str(r.output_path), - "start_time": r.start_time, - "end_time": r.end_time, - "duration": r.duration, - "file_size": r.file_size, - "success": r.success, - "error": r.error - } - for r in split_results_raw - ] # 创建切分摘要 successful_results = [r for r in split_results_raw if r.success] @@ -333,6 +319,79 @@ class BatchWorkflowNodes: # 切分失败不影响整体任务成功 # 4. 添加视频时长检查,如果时长大于 最大视频时长 那么就要进行二次切分 确保 视频不大于 最大视频时长 + final_split_results = [] + + for split_result in split_results_raw: + try: + # 检查切分后的视频时长 + video_path = str(split_result.output_path) + + if split_result.duration > state.max_video_duration: + logger.info(f"⚠️ 片段 {split_result.scene_index + 1} 时长 {split_result.duration:.2f}s 超过限制 {state.max_video_duration:.2f}s,进行二次切分") + + # 进行二次切分 + secondary_results = self.splitter_service.check_and_split_by_duration( + video_path=video_path, + max_duration=state.max_video_duration, + options=slice_options, + output_dir=str(split_result.output_path.parent) + ) + + # 处理二次切分结果 + for i, (secondary_path, secondary_metadata) in enumerate(secondary_results): + if len(secondary_results) > 1: + # 如果进行了二次切分,创建新的结果对象 + secondary_split_result = SplitResult( + scene_index=split_result.scene_index, + output_path=secondary_path, + start_time=split_result.start_time + (i * state.max_video_duration), + end_time=min(split_result.start_time + ((i + 1) * state.max_video_duration), split_result.end_time), + duration=secondary_metadata.duration, + file_size=secondary_metadata.size, + success=Path(secondary_path).exists(), + error=None if Path(secondary_path).exists() else "二次切分文件不存在" + ) + final_split_results.append(secondary_split_result) + + # 删除原始的过长片段(如果二次切分成功) + if Path(video_path).exists() and len(secondary_results) > 1: + try: + Path(video_path).unlink() + logger.info(f"🗑️ 已删除过长的原始片段: {Path(video_path).name}") + except Exception as e: + logger.warning(f"⚠️ 删除原始片段失败: {e}") + else: + # 如果没有进行二次切分(时长检查通过),保持原结果 + final_split_results.append(split_result) + else: + # 时长未超过限制,直接添加到最终结果 + final_split_results.append(split_result) + + except Exception as e: + logger.error(f"❌ 处理片段 {split_result.scene_index + 1} 的时长检查时出错: {e}") + # 出错时保持原结果 + final_split_results.append(split_result) + + # 使用最终的切分结果 + split_results_raw = final_split_results + + # 转换为字典格式 + split_results = [ + { + "scene_index": r.scene_index + 1, + "output_path": str(r.output_path), + "start_time": r.start_time, + "end_time": r.end_time, + "duration": r.duration, + "file_size": r.file_size, + "success": r.success, + "error": r.error + } + for r in split_results_raw + ] + + # 更新统计信息 + logger.info(f"📊 最终生成 {len(split_results_raw)} 个视频片段(包含二次切分)") task.end_time = time.time() diff --git a/python_core/scene_detection/workflows/workflow_manager.py b/python_core/scene_detection/workflows/workflow_manager.py index 2d0a838..85fab2b 100644 --- a/python_core/scene_detection/workflows/workflow_manager.py +++ b/python_core/scene_detection/workflows/workflow_manager.py @@ -184,7 +184,7 @@ class SceneDetectionWorkflowManager: enable_ai_analysis: bool = False, enable_video_splitting: bool = True, max_concurrent: int = 2, continue_on_error: bool = True, use_advanced_split: bool = True, split_quality: int = 23, split_preset: str = "fast", - request_id: Optional[str] = None) -> Dict[str, Any]: + max_video_duration: float = 60.0, request_id: Optional[str] = None) -> Dict[str, Any]: """批量场景检测和视频切分""" # 创建批量工作流状态 @@ -200,6 +200,7 @@ class SceneDetectionWorkflowManager: use_advanced_split=use_advanced_split, split_quality=split_quality, split_preset=split_preset, + max_video_duration=max_video_duration, max_concurrent=max_concurrent, continue_on_error=continue_on_error, request_id=request_id,