You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于MoviePy拼接视频:组合主/子视频生成≤60秒视频

问题背景与需求

1. 已分类的子视频集合

现有按时长分类的子视频集合sub_videos:

#  sub_videos ____________________________________________________________________________________
ten_second_or_below_videos = [ten_sec_video1, ten_sec_video2, ...]
twenty_second_or_below_videos = [twenty_sec_video10, twenty_sec_video12, ...]
thirty_second_or_below_videos = [thirty_sec_video10, thirty_sec_video12, ...]
forty_second_or_below_videos = [forty_sec_video15, forty_sec_video17, ...]
fifty_second_or_below_videos = [fifty_sec_video13, fifty_sec_video14, ...]
sixty_or_more_second_videos = [sixty_sec_video100, sixty_sec_video101, ...]
#  ^^^^^^^^^^^^^ everything above this will be called "sub_videos" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

各列表时长范围说明:

  • ten_second_or_below_videos:时长≤10秒
  • twenty_second_or_below_videos:10秒<时长≤20秒
  • thirty_second_or_below_videos:20秒<时长≤30秒
  • forty_second_or_below_videos:30秒<时长≤40秒
  • fifty_second_or_below_videos:40秒<时长≤50秒
  • sixty_or_more_second_videos:时长≥60秒

2. 未分类的主视频列表

另有未按时长排序的主视频列表:

main_videos = [ten_second_video1, twenty_second_video2, ten_second_video2, ...]

3. 核心需求

  • 从main_videos中选取一个视频
  • 搭配sub_videos中的任意数量视频(可重复选同类型)拼接
  • 最终拼接后的总时长必须≤60秒
  • 使用MoviePy工具完成拼接并导出视频文件

示例拼接结果:

FINAL_OUTPUT = [ten_second_main_video, ten_second_sub_video,ten_second_sub_video,
                ten_second_sub_video, ten_second_sub_video, ten_second_sub_video]

or

FINAL_OUTPUT = [EXACTLY_twenty_second_main_video, EXACTLY_twenty_second_sub_video, EXACTLY_twenty_second_sub_video]  
#  大写EXACTLY表示视频时长刚好为20秒

or

FINAL_OUTPUT = [ten_second_main_video, EXACTLY_thirty_second_sub_video,
                ten_second_sub_video, EXACTLY_ten_second_sub_video]

etc...

# 导出视频
concatenate_videoclips(FINAL_OUTPUT).write_videofile('video.mp4') # 导出文件时长≤60秒

实现方案

步骤1:预处理视频时长

先计算所有视频的精确时长,方便后续判断:

from moviepy.editor import VideoFileClip

# 计算主视频的精确时长,支持文件路径或已加载的VideoFileClip对象
main_video_durations = {}
for video in main_videos:
    if isinstance(video, str):
        clip = VideoFileClip(video)
        main_video_durations[video] = clip.duration
        clip.close()
    else:
        main_video_durations[video] = video.duration

# 计算子视频的精确时长,同时过滤掉≥60秒的无效视频
sub_video_durations = {}
# 把所有有效子视频(时长<60秒)整合到一起
valid_sub_groups = [
    ten_second_or_below_videos,
    twenty_second_or_below_videos,
    thirty_second_or_below_videos,
    forty_second_or_below_videos,
    fifty_second_or_below_videos
]
for group in valid_sub_groups:
    for video in group:
        if isinstance(video, str):
            clip = VideoFileClip(video)
            sub_video_durations[video] = clip.duration
            clip.close()
        else:
            sub_video_durations[video] = video.duration

步骤2:挑选符合条件的主视频

遍历主视频,筛选出时长≤60秒的视频,并计算剩余可用于拼接子视频的时长:

# 这里选第一个符合条件的主视频,也可以改成随机选或让用户指定
selected_main = None
remaining_time = 0
for video, dur in main_video_durations.items():
    if dur <= 60:
        selected_main = video
        remaining_time = 60 - dur
        break

if not selected_main:
    raise ValueError("所有主视频时长都超过60秒,无法进行拼接")

步骤3:挑选子视频组合

提供两种挑选逻辑,按需选择:

逻辑A:优先凑满接近60秒的组合

从最长的有效子视频开始选,尽量用最少的视频填满剩余时长:

def pick_max_fill_subs(remaining_time, sub_durations):
    # 过滤出时长≤剩余时间的子视频,按时长从大到小排序
    valid_subs = sorted(
        [(v, d) for v, d in sub_durations.items() if d <= remaining_time],
        key=lambda x: -x[1]
    )
    selected = []
    current_total = 0
    for video, dur in valid_subs:
        if current_total + dur <= remaining_time:
            selected.append(video)
            current_total += dur
            if current_total == remaining_time:
                break
    return selected

# 调用函数挑选子视频
selected_subs = pick_max_fill_subs(remaining_time, sub_video_durations)

逻辑B:随机挑选符合条件的子视频

适合需要多样化拼接结果的场景:

import random

def pick_random_subs(remaining_time, sub_durations):
    valid_subs = [v for v, d in sub_durations.items() if d <= remaining_time]
    selected = []
    current_total = 0
    while valid_subs:
        candidate = random.choice(valid_subs)
        candidate_dur = sub_durations[candidate]
        if current_total + candidate_dur <= remaining_time:
            selected.append(candidate)
            current_total += candidate_dur
        else:
            valid_subs.remove(candidate)
        # 剩余时间不够选最小的子视频时停止
        min_dur = min(sub_durations[v] for v in valid_subs) if valid_subs else float('inf')
        if remaining_time - current_total < min_dur:
            break
    return selected

# 调用函数挑选子视频
selected_subs = pick_random_subs(remaining_time, sub_video_durations)

步骤4:拼接并导出视频

from moviepy.editor import concatenate_videoclips

# 组合最终视频列表
final_output = [selected_main] + selected_subs

# 转换为VideoFileClip对象(如果传入的是文件路径)
final_clips = []
for item in final_output:
    if isinstance(item, str):
        final_clips.append(VideoFileClip(item))
    else:
        final_clips.append(item)

# 拼接并导出视频
concatenate_videoclips(final_clips).write_videofile('video.mp4')

# 关闭所有视频剪辑,释放资源
for clip in final_clips:
    clip.close()

补充说明

  • 自动过滤了sixty_or_more_second_videos中的视频,因为它们时长≥60秒,无法和任何主视频拼接
  • 如果需要精确凑满60秒,可以在挑选子视频时加入裁剪逻辑,比如用video.subclip(0, target_duration)截取子视频的部分内容
  • 可以扩展逻辑,支持批量生成多组不同的拼接组合,或者让用户手动选择主视频

内容的提问来源于stack exchange,提问作者HELPME

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 15:09:12