【Python】楽しようとmoviepy使ったのに結局ffmpeg
【状況】動画のトリミングを楽にしたくてmoviepyを使ってたのに,トリミングサイズの不具合が見つかった
【対処】ffmpegを使う
楽しようとしたけど
動画のトリミング&エンコードをしたくて,パッケージのインストールだけでよいmoviepy(1.0.3)を使っていたわけですが,特定の条件下においてトリミングサイズの不具合があることが分かりました.いつか修正されるかもしれませんが,ソースコードを書き換えないと使えなくなってしまうので今後のことを考えると,やりたいことが意図通り動くライブラリを使うのが吉でしょう.
ffmpegの設定
他でも解説はありますが一応メモします.
ダウンロードとフォルダの配置
実行形式を以下からダウンロードします.
https://ffmpeg.org/download.html
Windowsの場合,「Windows EXE Files」の「Windows builds by BtbN」を選択.「ffmpeg-master-latest-win64-gpl.zip」をダウンロードして展開します.
展開してできたフォルダを,例えばCドライブの直下に移動します.
その場合のパスは,「C:\ffmpeg-master-latest-win64-gpl」となります.
環境変数のパスの設定
環境変数の設定を行いますが,「システムのプロパティ」画面の出し方がいくつかあるようです.Windows11の場合,以下の手順でできます.
「スタートボタン」の右クリック→「システム」→「システムの詳細設定」を選ぶと,「システムのプロパティ」が出ます.
「システムのプロパティ」画面の「環境変数」ボタンを押し,下側の「システム環境変数」内の「Path」を選択して「編集」を押します.
「環境変数名の編集」画面で,「新規」を選択し出てきた空欄に,ffmpegの実行ファイルのパスをコピーして貼り付けます.Cドライブ直下に置いた場合,「C:\ffmpeg-master-latest-win64-gpl\bin」となります.
ターミナルかコマンドプロンプトを開き,「ffmpeg」と打つと,正常に設定できれいれば,大量の設定情報が出力されます.
ffmpeg version N-114583-g8e294abd9d-20240402 Copyright (c) 2000-2024 the FFmpeg developers
・
・
(大量の文字列)
・
・
Universal media converter
usage: ffmpeg [options] [[infile options] -i infile]... {[outfile options] outfile}...
ffmpeg-pythonのインストール
ffmpeg-pythonはffmpegをpythonから簡単に使えるようにするパッケージですね(最初はこれだけで良いのかと思ったら違った).
pip install ffmpeg-python
これでやっと準備完了です(これらが嫌で避けたのになぁ・・・).
以下,ffmpeg-pythonのリファレンスとサンプルです.参考まで.
リファレンス
https://kkroening.github.io/ffmpeg-python/
サンプル
https://github.com/kkroening/ffmpeg-python/tree/master/examples
ffmpeg-pythonで切り抜いて指定ビットレートでエンコード
以前作った関数crop_and_encodeの置き換えをします.引数は以下の要素です.
入力ファイル名
トリミングする座標(x1, y1)-(x2, y2)(左上と右下)
出力ファイル名
ビットレート(k)
ffmpegでは,左上の座標値と幅・高さを与えるので計算します.切り抜いたあとは,音声と動画をセットでエンコードします.
# 幅,高さを求める
width = x2 - x1 + 1
height = y2 - y1 + 1
input = ffmpeg.input(input_file) # 入力ファイル
video = ffmpeg.crop(input, x1, y1, width, height) # 左上座標と,幅・高さを与えてinputから切り抜く
audio = input.audio # 音声ファイルも一応inputからaudioに切り出す
out = ffmpeg.output(audio, video, output_file, video_bitrate = bitrate) # 音声,画像,ビットレートを指定してエンコードする
ffmpeg.run(out, overwrite_output=True) # 動画生成の実行(既存ファイルがある場合は上書き)
また,ffmpegにしたことで,ビットレートを直接取得できます(以前はOpenCVを利用).get_bitrateも差し替えます.
# 動画ファイルの情報を取得
video_info = ffmpeg.probe(file_path)
video_stream = next((stream for stream in video_info['streams'] if stream['codec_type'] == 'video'), None)
# ビットレートを取得
bitrate = int(video_stream['bit_rate'])
なお,ビットレートの扱いにおいて,moviepyとffmpegでは仕様が異なるので注意が必要です.moviepyは,与える数値の単位が[k]でしたが,ffmpegは,数値そのままです.100,000b/sの場合,
moviepy: 100 [kb/s]
ffmpeg: 100000 [b/s]
となります.
楽しようとしたのに,結局こんなに大量に作業が発生してしまうとか,あるあるですね.以前作ったプログラムも直さないと.
コード
import ffmpeg
# 元の動画のビットレートを取得
def get_bitrate(file_path): # ファイルパスを引数とする
# 動画ファイルの情報を取得
video_info = ffmpeg.probe(file_path)
video_stream = next((stream for stream in video_info['streams'] if stream['codec_type'] == 'video'), None)
# ビットレートを取得
bitrate = int(video_stream['bit_rate'])
print('bitrate : ', bitrate)
return bitrate
# 元の動画ファイルから切り抜いて,指定したビットレートでエンコードする
def crop_and_encode(input_file, x1, y1, x2, y2, output_file, bitrate):
# 幅,高さを求める
width = x2 - x1 + 1
height = y2 - y1 + 1
input = ffmpeg.input(input_file) # 入力ファイル
video = ffmpeg.crop(input, x1, y1, width, height) # 左上座標と,幅・高さを与えてinputから切り抜く
audio = input.audio # 音声ファイルも一応inputからaudioに切り出す
out = ffmpeg.output(audio, video, output_file, video_bitrate = bitrate) # 音声,画像,ビットレートを指定してエンコードする
ffmpeg.run(out, overwrite_output=True) # 動画生成の実行(既存ファイルがある場合は上書き)