制作卡点视频
python
import os
import pyJianYingDraft as draft
from pyJianYingDraft import trange, IntroType, TransitionType, tim
from PIL import Image
def jianying_time_to_microseconds(time_str: str, fps: int = 30) -> int:
"""
将剪映时间码(格式:'HH:MM:SS:FF')转换为微秒(μs)
参数:
time_str (str): 剪映时间码,例如 '00:00:02:11'
fps (int): 帧率,默认30
返回:
int: 转换后的微秒数
"""
parts = time_str.strip().split(':')
if len(parts) != 4:
raise ValueError("时间格式必须为 'HH:MM:SS:FF',例如 '00:00:02:11'")
try:
hours = int(parts[0])
minutes = int(parts[1])
seconds = int(parts[2])
frames = int(parts[3])
except ValueError as e:
raise ValueError("时间各部分必须为整数") from e
if frames >= fps:
raise ValueError(f"帧数 ({frames}) 不能大于或等于帧率 ({fps})")
# 计算总秒数(含小数)
total_seconds = hours * 3600 + minutes * 60 + seconds + frames / fps
# 转换为微秒(1秒 = 1e6微秒)
return int(round(total_seconds * 1_000_000))
def get_media_dimensions(media_path):
"""获取媒体文件的宽高尺寸"""
if media_path.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif')):
with Image.open(media_path) as img:
return img.size
elif media_path.lower().endswith(('.mp4', '.mov', '.avi', '.mkv')):
# 至少有一个视频,使用第一个视频的尺寸
first_video = draft.VideoMaterial(media_path)
width, height = first_video.width, first_video.height
return (width, height)
else:
raise ValueError(f"不支持的媒体类型: {media_path}")
def create_jianying_draft(draft_name, resource_paths, timecodes, draft_folder_path, bgm_path=None):
# 验证输入参数长度是否匹配
if len(resource_paths) != len(timecodes):
raise ValueError("资源文件路径列表与时间码列表长度不匹配")
# 获取第一个媒体文件的尺寸作为草稿尺寸
first_media = resource_paths[0]
width, height = get_media_dimensions(first_media)
# 创建草稿文件夹实例
draft_folder = draft.DraftFolder(draft_folder_path)
# 创建草稿(不允许覆盖)
try:
script = draft_folder.create_draft(draft_name, width, height, allow_replace=False)
except Exception as e:
raise RuntimeError(f"创建草稿失败: {str(e)}")
# 添加视频轨道和音频轨道
script.add_track(draft.TrackType.video)
script.add_track(draft.TrackType.audio) # 添加音频轨道用于放置背景音乐
for i, (media_path, timecode) in enumerate(zip(resource_paths, timecodes)):
start_str, end_str = timecode
# 转换时间格式为微秒
start_us = jianying_time_to_microseconds(start_str)
end_us = jianying_time_to_microseconds(end_str)
# 计算持续时间(微秒)
duration_us = end_us - start_us
if duration_us <= 0:
raise ValueError(f"无效的时间范围: 结束时间必须晚于开始时间 ({start_str} 至 {end_str})")
# 创建媒体片段
if media_path.lower().endswith(('.mp4', '.mov', '.avi', '.mkv')):
# 视频处理
video_material = draft.VideoMaterial(media_path)
media_duration = video_material.duration # 素材原始时长(微秒)
# 计算变速率
speed = media_duration / duration_us if duration_us != 0 else 1.0
# 创建视频片段(自动变速以适应目标时长)
segment = draft.VideoSegment(
video_material,
draft.Timerange(start_us, duration_us), # 直接使用微秒构造时间范围
speed=speed
)
else:
# 图片处理(图片默认持续时间为目标时长)
segment = draft.VideoSegment(
media_path,
draft.Timerange(start_us, duration_us) # 直接使用微秒构造时间范围
)
# 为第一个素材添加"动感缩小"动画
if i == 0:
segment.add_animation(IntroType.动感缩小, duration=duration_us)
# 为非第一个素材添加"闪回"转场(与前一个素材之间)
if i != len(resource_paths) - 1 :
# print("添加闪回转场")
transition_duration = tim("0.2s") # 0.2秒转场时长(微秒)
segment.add_transition(TransitionType.闪回, duration=transition_duration)
# 添加片段到视频轨道
script.add_segment(segment)
# 添加背景音乐
if bgm_path and os.path.exists(bgm_path):
try:
# 获取整个视频的总时长(最后一个片段的结束时间)
if timecodes:
last_end_str = timecodes[-1][1]
total_video_duration_us = jianying_time_to_microseconds(last_end_str)
# 创建音频素材
audio_material = draft.AudioMaterial(bgm_path)
# 创建音频片段,从0时刻开始,持续时间为视频总时长
audio_segment = draft.AudioSegment(
audio_material,
draft.Timerange(0, total_video_duration_us), # 使用音频素材的原始时长
volume=1.0 # 调整背景音乐音量(0.0-1.0)
)
# 添加到音频轨道(轨道索引1)
script.add_segment(audio_segment)
except Exception as e:
print(f"添加背景音乐时出错: {str(e)}")
# 保存草稿
script.save()
# 打印提示信息
print(f"素材已成功替换,新草稿名称{draft_name}")
return draft_name
# 示例用法
if __name__ == "__main__":
test_draft_name = "草稿名称04"
test_resources = ['D:\\Desktop\\快剪\\你的名字\\生成特定主题图片1.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片2.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片3.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片4.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片5.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片6.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片7.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片8.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片8.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片9.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片10.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片11.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片12.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片13.png']
#test_resources = ['D:\\Desktop\\快剪\\1月6日.mp4', 'D:\\Desktop\\test_folder\\jianying_materials_2\\videos\\02.mp4', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片3.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片4.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片5.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片6.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片7.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片8.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片8.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片9.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片10.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片11.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片12.png', 'D:\\Desktop\\快剪\\你的名字\\生成特定主题图片13.png']
test_timecodes = [['00:00:00:00', '00:00:02:11'], ['00:00:02:11', '00:00:02:25'],['00:00:02:25', '00:00:03:11'],['00:00:03:11', '00:00:03:27'],['00:00:03:27', '00:00:04:12'],['00:00:04:12', '00:00:04:26'],['00:00:04:26', '00:00:05:11'],['00:00:05:11', '00:00:05:25'],['00:00:05:25', '00:00:06:11'],['00:00:06:11', '00:00:06:27'],['00:00:06:27', '00:00:07:12'],['00:00:07:12', '00:00:07:27'],['00:00:07:27', '00:00:08:11'],['00:00:08:11', '00:00:08:26']]
test_folder = "D:\\download_software\\JianyingPro Drafts"
# 背景音乐文件路径
background_music_path = "D:\Desktop\快剪\卡点音乐.MP3"
try:
create_jianying_draft(
test_draft_name,
test_resources,
test_timecodes,
test_folder,
bgm_path=background_music_path # 传入背景音乐路径
)
except Exception as e:
print(f"发生错误: {str(e)}")