Update app.py
Browse files
app.py
CHANGED
|
@@ -522,8 +522,8 @@ def concat_videos(file_list, output_path):
|
|
| 522 |
except:
|
| 523 |
pass
|
| 524 |
|
| 525 |
-
def process_single_video(video_file, clip_duration, temp_dir):
|
| 526 |
-
"""[优化]
|
| 527 |
video_path = video_file.name
|
| 528 |
clips = []
|
| 529 |
try:
|
|
@@ -532,13 +532,19 @@ def process_single_video(video_file, clip_duration, temp_dir):
|
|
| 532 |
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
|
| 533 |
total_duration = float(result.stdout.strip())
|
| 534 |
print(f"视频总时长: {total_duration} 秒")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 535 |
except Exception as e:
|
| 536 |
print(f"处理视频 {video_path} 时获取时长失败: {e}")
|
| 537 |
return clips
|
| 538 |
|
| 539 |
start = 0.0
|
| 540 |
count = 0
|
| 541 |
-
while start < total_duration:
|
| 542 |
duration = min(clip_duration, total_duration - start)
|
| 543 |
# 修改文件名,包含原始文件名和计数,避免不同视频的切片重名
|
| 544 |
clip_path = os.path.join(temp_dir, f"clip_{os.path.splitext(os.path.basename(video_path))[0]}_{count}.mp4")
|
|
@@ -554,6 +560,7 @@ def process_single_video(video_file, clip_duration, temp_dir):
|
|
| 554 |
start += clip_duration
|
| 555 |
count += 1
|
| 556 |
|
|
|
|
| 557 |
return clips
|
| 558 |
|
| 559 |
def process_videos_with_storage(video_files, clip_duration, num_output_videos, target_ratio):
|
|
@@ -575,8 +582,15 @@ def process_videos_with_storage(video_files, clip_duration, num_output_videos, t
|
|
| 575 |
# 使用线程池进行并行处理(避免GIL限制)
|
| 576 |
print(f"🚀 启动并行切片({min(4, os.cpu_count() or 1)} 线程)...")
|
| 577 |
with concurrent.futures.ThreadPoolExecutor(max_workers=min(4, os.cpu_count() or 1)) as executor:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 578 |
future_to_video = {
|
| 579 |
-
executor.submit(process_single_video, vf, clip_duration, temp_dir): vf
|
| 580 |
for vf in video_files
|
| 581 |
}
|
| 582 |
|
|
@@ -597,6 +611,12 @@ def process_videos_with_storage(video_files, clip_duration, num_output_videos, t
|
|
| 597 |
if not all_clips:
|
| 598 |
return "❌ 切割失败,请检查视频文件", None, "", ""
|
| 599 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 600 |
random.shuffle(all_clips)
|
| 601 |
clips_per_video = max(1, len(all_clips) // num_output_videos)
|
| 602 |
output_files = []
|
|
@@ -808,7 +828,7 @@ def main():
|
|
| 808 |
|
| 809 |
with gr.Row():
|
| 810 |
clip_duration = gr.Number(value=3, label="切片时长(秒)", minimum=1, maximum=3600)
|
| 811 |
-
num_output = gr.Number(value=
|
| 812 |
|
| 813 |
ratio_selection = gr.Radio(
|
| 814 |
choices=["9:16", "16:9"],
|
|
@@ -952,6 +972,11 @@ def main():
|
|
| 952 |
- **快速预设**: 使用ultrafast预设提升速度
|
| 953 |
- **并行处理**: 多个视频同时处理
|
| 954 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 955 |
**⚠️ 注意事项:**
|
| 956 |
- 下载文件为ZIP格式,需要解压使用
|
| 957 |
- 一键下载包含储存空间中所有视频文件
|
|
|
|
| 522 |
except:
|
| 523 |
pass
|
| 524 |
|
| 525 |
+
def process_single_video(video_file, clip_duration, temp_dir, max_clips=50):
|
| 526 |
+
"""[优化] 处理单个视频文件,返回其所有切片路径的列表,限制最大片段数"""
|
| 527 |
video_path = video_file.name
|
| 528 |
clips = []
|
| 529 |
try:
|
|
|
|
| 532 |
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
|
| 533 |
total_duration = float(result.stdout.strip())
|
| 534 |
print(f"视频总时长: {total_duration} 秒")
|
| 535 |
+
|
| 536 |
+
# 计算需要多少个片段
|
| 537 |
+
max_possible_clips = int(total_duration / clip_duration) + 1
|
| 538 |
+
actual_max_clips = min(max_possible_clips, max_clips)
|
| 539 |
+
print(f"将生成最多 {actual_max_clips} 个片段")
|
| 540 |
+
|
| 541 |
except Exception as e:
|
| 542 |
print(f"处理视频 {video_path} 时获取时长失败: {e}")
|
| 543 |
return clips
|
| 544 |
|
| 545 |
start = 0.0
|
| 546 |
count = 0
|
| 547 |
+
while start < total_duration and count < actual_max_clips:
|
| 548 |
duration = min(clip_duration, total_duration - start)
|
| 549 |
# 修改文件名,包含原始文件名和计数,避免不同视频的切片重名
|
| 550 |
clip_path = os.path.join(temp_dir, f"clip_{os.path.splitext(os.path.basename(video_path))[0]}_{count}.mp4")
|
|
|
|
| 560 |
start += clip_duration
|
| 561 |
count += 1
|
| 562 |
|
| 563 |
+
print(f"实际生成 {len(clips)} 个片段")
|
| 564 |
return clips
|
| 565 |
|
| 566 |
def process_videos_with_storage(video_files, clip_duration, num_output_videos, target_ratio):
|
|
|
|
| 582 |
# 使用线程池进行并行处理(避免GIL限制)
|
| 583 |
print(f"🚀 启动并行切片({min(4, os.cpu_count() or 1)} 线程)...")
|
| 584 |
with concurrent.futures.ThreadPoolExecutor(max_workers=min(4, os.cpu_count() or 1)) as executor:
|
| 585 |
+
# 计算每个视频最多需要多少个片段
|
| 586 |
+
# 为了生成num_output_videos个混剪视频,每个混剪视频需要3-5个片段
|
| 587 |
+
# 所以总共需要大约 num_output_videos * 4 个片段
|
| 588 |
+
# 如果有多个视频,平均分配
|
| 589 |
+
total_needed_clips = num_output_videos * 4 # 每个混剪视频平均4个片段
|
| 590 |
+
clips_per_video = max(10, total_needed_clips // len(video_files)) # 每个视频至少10个片段
|
| 591 |
+
|
| 592 |
future_to_video = {
|
| 593 |
+
executor.submit(process_single_video, vf, clip_duration, temp_dir, clips_per_video): vf
|
| 594 |
for vf in video_files
|
| 595 |
}
|
| 596 |
|
|
|
|
| 611 |
if not all_clips:
|
| 612 |
return "❌ 切割失败,请检查视频文件", None, "", ""
|
| 613 |
|
| 614 |
+
# 如果片段太多,随机选择需要的数量
|
| 615 |
+
if len(all_clips) > total_needed_clips:
|
| 616 |
+
print(f"片段数量({len(all_clips)})超过需求({total_needed_clips}),随机选择...")
|
| 617 |
+
all_clips = random.sample(all_clips, total_needed_clips)
|
| 618 |
+
print(f"选择后剩余 {len(all_clips)} 个片段")
|
| 619 |
+
|
| 620 |
random.shuffle(all_clips)
|
| 621 |
clips_per_video = max(1, len(all_clips) // num_output_videos)
|
| 622 |
output_files = []
|
|
|
|
| 828 |
|
| 829 |
with gr.Row():
|
| 830 |
clip_duration = gr.Number(value=3, label="切片时长(秒)", minimum=1, maximum=3600)
|
| 831 |
+
num_output = gr.Number(value=5, label="生成数量", minimum=1, maximum=100)
|
| 832 |
|
| 833 |
ratio_selection = gr.Radio(
|
| 834 |
choices=["9:16", "16:9"],
|
|
|
|
| 972 |
- **快速预设**: 使用ultrafast预设提升速度
|
| 973 |
- **并行处理**: 多个视频同时处理
|
| 974 |
|
| 975 |
+
**🎯 智能切片:**
|
| 976 |
+
- **按需生成**: 根据要生成的视频数量智能计算需要的片段数
|
| 977 |
+
- **避免冗余**: 不会生成超过需要的片段,节省处理时间
|
| 978 |
+
- **随机选择**: 从生成的片段中随机选择,确保混剪多样性
|
| 979 |
+
|
| 980 |
**⚠️ 注意事项:**
|
| 981 |
- 下载文件为ZIP格式,需要解压使用
|
| 982 |
- 一键下载包含储存空间中所有视频文件
|