Python---批量给视频添加片头片尾

在剪辑视频的时候,如果视频很少的情况可以考虑自己使用软件来拼接一下,但是如果要给几百个视频加片头片尾,那就需要使用软件来加了。

基础代码示例:

from moviepy.editor import VideoFileClip, concatenate_videoclips

# 读取三段视频
piantou = VideoFileClip("piantou-10000k-25f.mp4")
video = VideoFileClip("video.mp4")
pianwei = VideoFileClip("pianwei-10000k-25f.mp4")
# 拼接并导出
outvideo = concatenate_videoclips([piantou, video, pianwei])
outvideo.write_videofile("outvideo.mp4")

这种方式可以给一个视频添加片头片尾。

批量给视频视频添加片头片尾:

import os
import re
import time
import subprocess
from multiprocessing import Pool
from typing import List, Dict


# 配置路径
INPUT_VIDEO_DIR = r"E:\python-test\视频处理\原视频"  # 原视频文件夹
OUTPUT_VIDEO_DIR = r"E:\python-test\视频处理\带片头片尾视频"  # 输出文件夹
OPENING_VIDEO = r"E:\python-test\视频处理\piantou-tongyi.mp4"  # 片头视频路径
ENDING_VIDEO = r"E:\python-test\视频处理\pianwei-tongyi.mp4"  # 片尾视频路径

# 支持的视频格式(可扩展)
SUPPORTED_FORMATS = ('.mp4', '.avi', '.mov', '.mkv', '.flv', '.wmv')


def check_dependencies() -> bool:
    """检查ffmpeg是否可用及片头片尾文件是否存在"""
    # 检查ffmpeg
    try:
        subprocess.run(['ffmpeg', '-version'], capture_output=True, check=True)
    except (subprocess.CalledProcessError, FileNotFoundError):
        print("错误:未找到ffmpeg!请安装并配置环境变量")
        return False

    # 检查片头文件
    if not os.path.exists(OPENING_VIDEO):
        print(f"错误:片头文件不存在 - {OPENING_VIDEO}")
        return False

    # 检查片尾文件
    if not os.path.exists(ENDING_VIDEO):
        print(f"错误:片尾文件不存在 - {ENDING_VIDEO}")
        return False

    return True


def get_video_duration(file_path: str) -> float:
    """获取视频时长(秒)"""
    try:
        result = subprocess.run(
            ['ffmpeg', '-i', file_path],
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            encoding='utf-8',
            errors='ignore'
        )
        # 匹配时长格式(如:Duration: 00:01:23.45)
        pattern = re.compile(r"Duration:\s*(\d+):(\d+):(\d+\.\d+)")
        match = pattern.search(result.stdout)
        if not match:
            return -1

        hours = float(match.group(1))
        minutes = float(match.group(2))
        seconds = float(match.group(3))
        return hours * 3600 + minutes * 60 + seconds
    except Exception as e:
        print(f"获取时长失败:{file_path},错误:{str(e)}")
        return -1


def concat_videos(opening: str, main_video: str, ending: str, output: str) -> bool:
    """拼接片头、主视频、片尾"""
    # 确保输出目录存在
    os.makedirs(os.path.dirname(output), exist_ok=True)

    # 创建临时文件列表(ffmpeg拼接需要的文件列表)
    temp_list = f"{output}.txt"
    try:
        with open(temp_list, 'w', encoding='utf-8') as f:
            f.write(f"file '{opening}'\n")
            f.write(f"file '{main_video}'\n")
            f.write(f"file '{ending}'\n")

        # ffmpeg命令:使用concat协议拼接(快速,无需重新编码)
        command = [
            'ffmpeg', '-f', 'concat', '-safe', '0', '-i', temp_list,
            '-c', 'copy', '-y',  # -y:覆盖已有文件
            output
        ]

        result = subprocess.run(
            command,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            encoding='utf-8',
            errors='ignore',
            timeout=600  # 超时时间10分钟
        )

        if result.returncode != 0:
            print(f"拼接失败:{main_video},错误:{result.stderr[:500]}")
            return False
        print(f"拼接成功:{output}")
        return True
    except Exception as e:
        print(f"拼接异常:{main_video},错误:{str(e)}")
        return False
    finally:
        # 清理临时文件
        if os.path.exists(temp_list):
            try:
                os.remove(temp_list)
            except:
                pass


def process_single_video(task: Dict[str, str]) -> None:
    """处理单个视频的函数(供多进程调用)"""
    main_video = task['main_video']
    output_video = task['output_video']

    # 检查原视频是否有效
    duration = get_video_duration(main_video)
    if duration <= 0:
        print(f"跳过无效视频:{main_video}")
        return

    # 执行拼接
    concat_videos(
        opening=OPENING_VIDEO,
        main_video=main_video,
        ending=ENDING_VIDEO,
        output=output_video
    )


def get_all_videos(folder: str) -> List[str]:
    """递归获取所有支持的视频文件"""
    video_files = []
    for root, _, files in os.walk(folder):
        for file in files:
            if file.lower().endswith(SUPPORTED_FORMATS):
                video_files.append(os.path.join(root, file))
    return video_files


if __name__ == "__main__":
    # 检查依赖
    if not check_dependencies():
        input("按回车键退出...")
        exit(1)

    # 获取所有视频文件
    video_files = get_all_videos(INPUT_VIDEO_DIR)
    if not video_files:
        print(f"未在 {INPUT_VIDEO_DIR} 找到支持的视频文件(格式:{SUPPORTED_FORMATS})")
        input("按回车键退出...")
        exit(0)
    print(f"共找到 {len(video_files)} 个视频文件,准备添加片头片尾...")

    # 构建任务列表(保持原文件目录结构)
    tasks = []
    for video in video_files:
        # 计算输出路径(保持原目录结构)
        relative_path = os.path.relpath(video, INPUT_VIDEO_DIR)
        output_path = os.path.join(OUTPUT_VIDEO_DIR, relative_path)
        tasks.append({
            'main_video': video,
            'output_video': output_path
        })

    # 多进程处理
    start_time = time.time()
    print("\n开始处理...")
    # 进程数设为CPU核心数的一半,避免资源占用过高
    with Pool(processes=os.cpu_count() // 2) as pool:
        pool.map(process_single_video, tasks)

    # 统计结果
    total_time = time.time() - start_time
    print(f"\n处理完成!共处理 {len(video_files)} 个视频,耗时 {total_time:.2f} 秒")
    print(f"输出目录:{OUTPUT_VIDEO_DIR}")
    input("按回车键退出...")

简直了YYDS!

打完收工!

posted @ 2025-10-24 16:02  帅到要去报警  阅读(5)  评论(0)    收藏  举报