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

    Django

    pipenv shellをしてもactivateできない

    pipenv shellをしてもactivateできない pipenvで作った仮想環境に出たり入ったりを繰り返していると、pipenv shellをしても以下のようにShell for UNKNOWN_VIRTUAL_E […]

    Posted on by press
    Python

    Pythonのargparseでコマンドライン引数をパース

    Pythonのargparseでコマンドライン引数をパース argparseモジュールを使って、Pythonを実行する際にコマンドライン引数を指定してプログラム内に情報を渡す方法です。 引数によって処理を変えたり、別々の […]

    Posted on by press

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

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

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