制作卡点视频

制作卡点视频

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)}")
相关推荐
子超兄1 天前
慢查询处理SOP
数据库
owlion1 天前
如何将视频文案整理成学习笔记
人工智能·python·机器学习·语言模型·自然语言处理
癫狂的兔子1 天前
【Python】【NumPy】random.rand和random.uniform的异同点
开发语言·python·numpy
TDengine (老段)1 天前
TDengine C/C++ 连接器入门指南
大数据·c语言·数据库·c++·物联网·时序数据库·tdengine
Lupino1 天前
aio_periodic 重构与优化实战:构建高性能 Python 定时任务客户端
python·haskell
地球资源数据云1 天前
2019-2024年中国逐年10米分辨率最大值合成NDVI数据集
大数据·运维·服务器·数据库·均值算法
先做个垃圾出来………1 天前
Python整数存储与位运算
开发语言·python
自燃人~1 天前
怎么优化慢SQL
数据库·sql
RAY_01041 天前
Python—面向对象
python