PythonとMoviePyで動画ファイルの指定時間ごとの分割を自動化


press
PythonとMoviePyで動画ファイルの指定時間ごとの分割を自動化

PythonとMoviePyで動画ファイルの指定時間ごとの分割を自動化

OpenCVなどで動画の処理を行う際に、1分毎の変化や10分毎に結果を見たいときに一連の動画から指定した時間毎に分割して切り出したいことがあります。動画編集ソフトを使っても良いですが動画の切り出しという単調な作業の繰り返しで人的ミスも発生しやすくなるため、できれば自動化させたい処理の一つです。本記事では動画の分割作業をPythonとMoviePyで自動化する方法を解説します。

コードはGitHubリポジトリにあげています。

開発環境

PC: MacBook Pro (14, 2021)
OS: macOS Monterey 12.0.1
Python: 3.9.1
moviepy: 1.0.3

import os
import glob
import sys

from moviepy.video.io.VideoFileClip import VideoFileClip
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip


def split_video(file_path: str, duration: int) -> None:
    # ファイル名から拡張子を取得
    file_name, file_extension = os.path.splitext(os.path.basename(file_path))

    # 分割したビデオの保存先ディレクトリを作成
    output_dir = f"{file_name}_split"
    os.makedirs(output_dir, exist_ok=True)

    # 動画の長さを取得し、動画ファイルを適切に閉じる
    with VideoFileClip(file_path) as video:
        total_duration = int(video.duration)

    # 指定した間隔でビデオを分割
    start_time = 0
    end_time = duration

    while start_time < total_duration:
        # 実際の終了時間が動画の総時間を超えないように調整
        end_time = min(end_time, total_duration)

        # 分割範囲を指定してビデオを切り出し
        output_path = os.path.join(output_dir, f"{file_name}_{start_time}_{end_time}{file_extension}")
        ffmpeg_extract_subclip(file_path, start_time, end_time, targetname=output_path)

        # 次の分割範囲を更新
        start_time += duration
        end_time = start_time + duration


def split_videos_in_directory(directory: str, duration: int) -> None:
    # ディレクトリ内のすべてのMP4ファイルを取得
    video_files = glob.glob(os.path.join(directory, "*.mp4"))
    for video_file in video_files:
        # 動画ファイル毎に分割処理
        split_video(video_file, duration)


# メイン処理
if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("ディレクトリパスを引数として指定してください。")
        sys.exit(1)

    directory_path = sys.argv[1]
    if not os.path.isdir(directory_path):
        print("指定されたパスはディレクトリではありません。")
        sys.exit(1)

    # コマンドライン引数からdurationを取得し、指定がない場合は600秒をデフォルト値とする
    try:
        duration = int(sys.argv[2]) if len(sys.argv) > 2 else 600
    except ValueError:
        print("Durationは整数である必要があります。")
        sys.exit(1)

    split_videos_in_directory(directory_path, duration)

解説

コードの量が少し多いですが大きく分けると以下の3つの処理に分けられます。

  1. 動画を指定した時間毎に分割
  2. ディレクトリから動画ファイルを取得
  3. 引数を受け取って上記の処理を実行
import os
import glob
import sys

from moviepy.video.io.VideoFileClip import VideoFileClip
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip

ライブラリ、モジュールのインポート

def split_video(file_path: str, duration: int) -> None:
    # ファイル名から拡張子を取得
    file_name, file_extension = os.path.splitext(os.path.basename(file_path))

    # 分割したビデオの保存先ディレクトリを作成
    output_dir = f"{file_name}_split"
    os.makedirs(output_dir, exist_ok=True)

    # 動画の長さを取得し、動画ファイルを適切に閉じる
    with VideoFileClip(file_path) as video:
        total_duration = int(video.duration)

    # 指定した間隔でビデオを分割
    start_time = 0
    end_time = duration

    while start_time < total_duration:
        # 実際の終了時間が動画の総時間を超えないように調整
        end_time = min(end_time, total_duration)

        # 分割範囲を指定してビデオを切り出し
        output_path = os.path.join(output_dir, f"{file_name}_{start_time}_{end_time}{file_extension}")
        ffmpeg_extract_subclip(file_path, start_time, end_time, targetname=output_path)

        # 次の分割範囲を更新
        start_time += duration
        end_time = start_time + duration

取得したファイルを指定した時間毎に分割して保存する関数

def split_videos_in_directory(directory: str, duration: int) -> None:
    # ディレクトリ内のすべてのMP4ファイルを取得
    video_files = glob.glob(os.path.join(directory, "*.mp4"))
    for video_file in video_files:
        # 動画ファイル毎に分割処理
        split_video(video_file, duration)

ディレクトリ内のファイル(mp4のみ)を取得して処理する関数
取得したファイルを1件づつ先述の動画を分割する関数に渡す

# メイン処理
if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("ディレクトリパスを引数として指定してください。")
        sys.exit(1)

    directory_path = sys.argv[1]
    if not os.path.isdir(directory_path):
        print("指定されたパスはディレクトリではありません。")
        sys.exit(1)

    # コマンドライン引数からdurationを取得し、指定がない場合は600秒をデフォルト値とする
    try:
        duration = int(sys.argv[2]) if len(sys.argv) > 2 else 600
    except ValueError:
        print("Durationは整数である必要があります。")
        sys.exit(1)

    split_videos_in_directory(directory_path, duration)

引数にはディレクトリのパスと分割する時間をフレームレートで指定
フレームレートの指定がない場合は600フレームを指定(30フレームの動画の場合10分)
ディレクトリのパスとフレームレートに異常がある場合はエラーを発生させる


株式会社ファントムへのお問い合わせ

群馬県でPythonを使ったAIやソフトウェアを開発している株式会社ファントムが運営しています。




    Related Articles

    Python

    OpenCVで複数の動画を連結する

    OpenCVで複数の動画を連結する 複数の動画素材を結合したり、GoProで長時間撮影した時に約4GB毎に分割される動画ファイルを結合して一つの動画を書き出す方法です。 コードはGitHubリポジトリにあげています。 開 […]

    Posted on by press
    Python

    Pythonのenumerate関数でfor文のインデックスを取得

    Pythonのenumerate関数でfor文のインデックスを取得 enumerate関数を使うとPythonでforを書くときに処理毎にカウントアップしたり、値を代入したりといった処理が簡単にできるので便利です。 実際 […]

    Posted on by press

    最新情報をお届けします!

    メーリングリストに登録するとファントムの最新情報をお届けします

    お客様のメールアドレスを共有することはありません