fix: 视频切分

This commit is contained in:
root
2025-07-12 15:10:38 +08:00
parent d079d2a6a8
commit 5659bb34f3
4 changed files with 616 additions and 720 deletions

View File

@@ -41,9 +41,10 @@ class BatchSceneDetectionWorkflowState:
use_advanced_split: bool = True
split_quality: int = 23
split_preset: str = "fast"
max_video_duration: float = 60.0 # 最大视频时长默认60秒
# 批量处理配置
max_concurrent: int = 2
max_concurrent: int = 4
continue_on_error: bool = True
# 工作流状态

View File

@@ -5,9 +5,8 @@ Batch Workflow Nodes
"""
import time
import asyncio
from pathlib import Path
from typing import Dict, Any, List
from typing import Dict, Any
from concurrent.futures import ThreadPoolExecutor, as_completed
from python_core.utils.logger import logger
@@ -17,7 +16,7 @@ from ..types.enums import DetectorType, OutputFormat
from ..services.detector_service import SceneDetectorService
from ..services.video_info_service import VideoInfoService
from ..services.ai_analysis_service import AIAnalysisService
from python_core.services.ffmpeg_slice_service import FfmpegSliceService, SliceOptions
from python_core.services.ffmpeg_slice_service_sync import FfmpegSliceService, SliceOptions, SliceSegment
from ..utils.result_saver import ResultSaver
@@ -202,13 +201,100 @@ class BatchWorkflowNodes:
preset=state.split_preset
)
split_results_raw = self.splitter_service.split_video_by_scenes(
task.video_path,
detection_result.scenes,
task.output_dir / "scenes",
use_advanced=state.use_advanced_split,
options=slice_options
)
# 转换场景为SliceSegment
segments = [
SliceSegment(start=scene.start_time, end=scene.end_time)
for scene in detection_result.scenes
]
# 创建输出目录
scenes_dir = task.output_dir / "scenes"
scenes_dir.mkdir(parents=True, exist_ok=True)
# 生成输出路径
base_output_path = str(scenes_dir / f"{task.video_path.stem}_scene")
# 使用同步方法进行切分
# 检查是否无场景,如果是则跳过切分
if len(segments) <= 0:
logger.info(f"🔄 检测到 0 个场景切换,跳过切分,直接使用源文件")
# 创建输出目录
scenes_dir.mkdir(parents=True, exist_ok=True)
# 直接复制源文件作为结果
import shutil
source_file = task.video_path
target_file = scenes_dir / f"{task.video_path.stem}_scene_001.mp4"
try:
shutil.copy2(source_file, target_file)
logger.info(f"✅ 源文件已复制到: {target_file}")
# 获取源文件元数据
metadata = self.splitter_service.get_video_metadata(str(source_file))
# 创建模拟的切分结果
slice_results = [(str(target_file), metadata)]
# 修正场景统计:无场景切换 = 1个场景整个视频
detection_result.total_scenes = 1
except Exception as e:
logger.error(f"❌ 复制源文件失败: {e}")
slice_results = []
else:
logger.info(f"🎬 检测到 {len(segments)} 个场景,开始切分")
slice_results = self.splitter_service.slice_video(
media_path=str(task.video_path),
segments=segments,
options=slice_options,
output_path=base_output_path
)
# 转换为兼容格式
split_results_raw = []
# 创建一个简单的结果对象
class SplitResult:
def __init__(self, scene_index, output_path, start_time, end_time, duration, file_size, success, error=None):
self.scene_index = scene_index
self.output_path = Path(output_path)
self.start_time = start_time
self.end_time = end_time
self.duration = duration
self.file_size = file_size
self.success = success
self.error = error
for i, (output_path, metadata) in enumerate(slice_results):
if len(detection_result.scenes) == 0:
# 无场景切换的情况:整个视频作为一个场景
split_result = SplitResult(
scene_index=0,
output_path=output_path,
start_time=0.0,
end_time=metadata.duration,
duration=metadata.duration,
file_size=metadata.size,
success=Path(output_path).exists(),
error=None if Path(output_path).exists() else "文件不存在"
)
split_results_raw.append(split_result)
else:
# 有场景切换的情况
scene = detection_result.scenes[i] if i < len(detection_result.scenes) else None
if scene:
split_result = SplitResult(
scene_index=i,
output_path=output_path,
start_time=scene.start_time,
end_time=scene.end_time,
duration=scene.duration,
file_size=metadata.size,
success=Path(output_path).exists(),
error=None if Path(output_path).exists() else "文件不存在"
)
split_results_raw.append(split_result)
# 转换为字典格式
split_results = [
@@ -225,10 +311,18 @@ class BatchWorkflowNodes:
for r in split_results_raw
]
# 保存切分摘要
split_summary = self.splitter_service.create_split_summary(
task.video_path, split_results_raw
)
# 创建切分摘要
successful_results = [r for r in split_results_raw if r.success]
failed_results = [r for r in split_results_raw if not r.success]
split_summary = {
"video_path": str(task.video_path),
"total_scenes": len(split_results_raw),
"successful_splits": len(successful_results),
"failed_splits": len(failed_results),
"success_rate": len(successful_results) / len(split_results_raw) * 100 if split_results_raw else 0,
"total_output_size": sum(r.file_size for r in successful_results)
}
summary_file = task.output_dir / "split_summary.json"
import json
with open(summary_file, 'w', encoding='utf-8') as f:
@@ -238,6 +332,8 @@ class BatchWorkflowNodes:
logger.error(f"视频切分失败: {e}")
# 切分失败不影响整体任务成功
# 4. 添加视频时长检查,如果时长大于 最大视频时长 那么就要进行二次切分 确保 视频不大于 最大视频时长
task.end_time = time.time()
return {