はじめに
本格的な動画編集には GUI を備えた専用ソフトを使うのが適している。しかし、大量の動画を一括で結合・変換するなど、軽い操作を効率的にこなせるツールがないか探していたところ、moviepy にたどり着いた。
動画ファイルの「カット」「分離」「結合」「テキスト挿入」「fps 変換」といった基本的な編集を、わずか数行のコードで実現できる。本記事では、そんな moviepy のユースケースをまとめて紹介する。
目次
モジュールのインストール
pip install moviepyでモジュールをインストールする。注意点としてv2.0以降(2024.11~)でモジュールの読み出し方が大きく変わっているよう。
#v2.0以降
from moviepy import VideoFileClip
#以前
from moviepy.editor import VideoFileClip
この記事で扱うモジュール
| import | 概要 |
|---|---|
| VideoFileClip | 動画ファイルを読み込み |
| concatenate_videoclips | 複数動画を結合 |
| vfx | 効果をつける |
| TextClip | テキストを動画化 |
| CompositeVideoClip | 複数動画を合成 |
動画の読み込み
moviepy は、動画、画像でよく使われる下記フォーマットの対応をしている。その他、FFmpeg が読み書きできる形式は全て対応している。
| フォーマット | |
|---|---|
| 動画 | .mp4 .mts(AVCHD) .mov .mkv .avi |
| 画像 | .png .jpg .gif |
VideoFileClip()で動画ファイル名を指定すると動画データを読みだす。読みだしたデータの詳細情報は.reader.infosで取得できる。close()読み込んだファイルをcloseする。
from moviepy import VideoFileClip, TextClip, CompositeVideoClip
from pprint import pprint
# 動画ファイル読み込み
filename = 'input01.MTS'
videoclip = VideoFileClip(filename)
# 基本情報
print(f'{videoclip.filename=}')
print(f'{videoclip.duration=}')
print(f'{videoclip.size=}')
print(f'{videoclip.fps=}')
print(f'{videoclip.aspect_ratio=}')
# 詳細情報
pprint(videoclip.reader.infos)
# close
videoclip.close()
'''
----------
videoclip.filename='input01.MTS' # ファイル名
videoclip.duration=31.55 # 時間[s]
videoclip.size=[1920, 1080] # サイズ
videoclip.fps=29.97002997002997 # FPS
videoclip.aspect_ratio=1.7777777777777777 # アスペクト比
----------
{'audio_bitrate': 384,
'audio_found': True,
'audio_fps': 48000,
'bitrate': 8100,
'default_audio_input_number': 0,
'default_audio_stream_number': 1,
'default_video_input_number': 0,
'default_video_stream_number': 0,
'duration': 31.55,
'inputs': [{'input_number': 0,
'streams': [{'bitrate': None,
'codec_name': 'h264',
'default': True,
'fps': 29.97002997002997,
'input_number': 0,
'language': None,
'profile': '(High)',
'size': [1920, 1080],
'stream_number': 0,
'stream_type': 'video'},
{'bitrate': 384,
'default': True,
'fps': 48000,
'input_number': 0,
'language': None,
'stream_number': 1,
'stream_type': 'audio'}]}],
'metadata': {},
'start': 0.8347,
'video_bitrate': None,
'video_codec_name': 'h264',
'video_duration': 31.55,
'video_found': True,
'video_fps': 29.97002997002997,
'video_n_frames': 945,
'video_profile': '(High)',
'video_size': [1920, 1080]}
'''
動画の分離・結合
subclipped(start,end)で秒数を指定して切り取り分離ができる。マイナス値を指定することもできる。結合はconcatenate_videoclips([])で結合ファイルを順番にリストで指定する。最後に.write_videofile()で出力ファイル名を指定して保存する。
from moviepy import VideoFileClip, concatenate_videoclips
# 動画ファイル2ファイル読み込み
filename1 = 'input01.MTS'
videoclip1 = VideoFileClip(filename1)
filename2 = 'input02.MTS'
videoclip2 = VideoFileClip(filename2)
#カット 1. 最初~10秒
cut1 = videoclip1.subclipped(0,10)
#カット 2. 10秒前~最後
cut2 = videoclip2.subclipped(-10,videoclip2.duration)
# 結合
outclip = concatenate_videoclips([cut1,cut2])
# 保存
outclip.write_videofile('out.mp4')
videoclip1.close()
videoclip2.close()
動画に効果をつける
フェードイン、フェードアウト、0.5倍速、2倍速、モノクロなど、動画に効果をつけるときは.with_effects([効果を列挙])を使う。効果は、配列で複数列挙することもできる。
| 効果 | 指定 |
|---|---|
| フェードイン | vfx.FadeIn(秒数) |
| フェードアウト | vfx.FadeOut(秒数) |
| 倍速 | vfx.MultiplySpeed(倍速値) |
| モノクロ | vfx.BlackAndWhite() |
from moviepy import VideoFileClip, vfx
# 動画ファイルファイル読み込み
filename1 = 'input01.MTS'
videoclip1 = VideoFileClip(filename1)
# フェードインフェードアウト
vfead = videoclip1.with_effects([vfx.FadeIn(2), vfx.FadeOut(2)])
vfead.write_videofile('vfead.mp4')
# 0.5倍速
slow = videoclip1.with_effects([vfx.MultiplySpeed(0.5)])
slow.write_videofile('slow.mp4')
# 2.0倍速
fast = videoclip1.with_effects([vfx.MultiplySpeed(2)])
fast.write_videofile('fast.mp4')
# モノクロ
whiteblack = videoclip1.with_effects([vfx.BlackAndWhite()])
whiteblack.write_videofile('whiteblack.mp4')
videoclip1.close()
テキスト挿入
動画の撮影日を表示するなどの場合テキスト挿入ができる。テキストを挿入する場合はTextClipを使う。その後、作ったテキストデータをCompositeVideoClipで結合する。日本語を扱う場合は、fontを指定しないと文字化けするので注意。windowsの場合は、C:\Windows\Fontsにfontが保存されているのでここから選択する。
テキストは表示開始時間、表示時間、表示位置などを指定できる。
from moviepy import VideoFileClip, TextClip, CompositeVideoClip
import os, datetime
# 動画ファイルファイル読み込み
filename1 = 'input01.MTS'
videoclip1 = VideoFileClip(filename1)
# ファイルの更新日時取得
dt = datetime.datetime.fromtimestamp(os.path.getmtime(filename1))
dt = dt.strftime("%Y年%m月%d日 %H:%M:%S")
# text
# 日本語の場合はfontを指定すること。
# with_position は 水平(left, right)、垂直(top,center,bottom)の順
txt =TextClip(font='C:\Windows\Fonts\meiryo.ttc', font_size=100,color='white',text=dt).with_start(2).with_duration(5).with_position(("right", "bottom"))
#結合
outclip = CompositeVideoClip([videoclip1,txt])
# 保存
outclip.write_videofile('text.mp4')
videoclip1.close()
動画の画面をトリミングする
動画の画面をトリミングする場合は.cropped()を使う
from moviepy import VideoFileClip
# 動画ファイルファイル読み込み
filename1 = 'input01.MTS'
videoclip1 = VideoFileClip(filename1)
#トリミングする
cropped = videoclip1.cropped(x1=0, y1=0, x2=940, y2=760)
# 保存
cropped.write_videofile('cropped.mp4')
videoclip1.close()
GIFファイルにする
動画を保存するときにfpsを指定するとGIFファイルとして保存することもできる。moviepyの便利なのは、保存時にファイル名を指定してあげるとそれに合わせたコーデックもしてくれるところ。Qiitaの記事で動きのある映像を載せたい場合にこのGIF化が簡単にできる、moviepyは便利。
from moviepy import VideoFileClip
# 動画ファイルファイル読み込み
filename1 = 'input01.MTS'
videoclip1 = VideoFileClip(filename1)
# 保存 fps=5 (200msに1画像)
videoclip1.write_gif('out.gif', fps=5)
videoclip1.close()