fix: 视频切分
This commit is contained in:
@@ -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
|
||||
|
||||
# 工作流状态
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user