LoginSignup
50
57

More than 3 years have passed since last update.

ffmpeg-pythonで動画編集する

Posted at

ffmpeg-python

ffmpeg-pythonはffmpegをpythonから使えるようにするパッケージです

github
https://github.com/kkroening/ffmpeg-python

API-reference
https://kkroening.github.io/ffmpeg-python/

使用例
https://github.com/kkroening/ffmpeg-python/tree/master/examples

1. インストール

ffmpeg-pythonはsubprocessでCLIからffmpegを実行するwrapperのみのパッケージなので、別途本体をダウンロードしてきてPATHを通しておく必要があります。

1-1. ffmpegをインストールする

公式サイトからインストーラーをダウンロードしてきて入れます
https://ffmpeg.org/download.html

落としてきた圧縮ファイルを適当なフォルダに展開して、binフォルダにPATHを通せばインストール完了です
image.png
PATHが通ってれば以下のようにterminalから呼べるようになっている筈です

terminal
> ffmpeg

ffmpeg version 2021-03-07-git-a7f841718f-full_build-www.gyan.dev Copyright (c) 2000-2021 the FFmpeg developers
  built with gcc 10.2.0 (Rev6, Built by MSYS2 project)

1-2. ffmpeg-pythonをインストールする

pipで入ります

terminal
pip install ffmpeg-python

2. 動画ファイルの情報を取得する

ffmpeg.probe()に動画ファイルのpathを渡すとdictで取得した情報を返してくれます

python
>>> import ffmpeg
>>> path = './movie.mp4'
>>> video_info = ffmpeg.probe(path)
>>> video_info

{'streams': [{'index': 0,
   'codec_name': 'h264',
   'codec_long_name': 'H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10',
   'profile': 'High',
   'codec_type': 'video',
   'codec_tag_string': 'avc1',
   'codec_tag': '0x31637661',
   'width': 1920,
   'height': 1080,
   'coded_width': 1920,
   'coded_height': 1080, 
   ...

3. 使い方

処理する内容をパイプライン的に積み上げておいて、最後にffmpeg.run()することで実行されます。以下ではinput()で読み込んで、hflip()で左右反転して、output()で書き出すという処理になります

python
stream = ffmpeg.input('movie.mp4')
stream = ffmpeg.hflip(stream)
stream = ffmpeg.output(stream, 'output.mp4')
ffmpeg.run(stream)

同じことを次のように書くことも出来ます

python
stream = ffmpeg.input('movie.mp4').hflip().output('output.mp4')
ffmpeg.run(stream)

4. 動画を加工する

4-1. 読み込み/書き出し範囲を指定する

開始時間ssと動画時間tを指定することで動画の一部だけ読み書き出来ます

読み込みで範囲指定
stream = ffmpeg.input('./movie.mp4', ss=2, t=2)
書き出しで範囲指定
stream = ffmpeg.output(stream, 'output.mp4', ss=2, t=2)

4-2. 画像を反転する

左右反転
stream = ffmpeg.hflip(stream)
上下反転
stream = ffmpeg.vflip(stream)

4-3. 音声トラックを分離して処理する場合

画像フィルタによっては音声トラックが消えてしまうものがありますので、その場合はフィルタをかける前に音声を分けておいて、後で結合してやる必要があります

python
stream = ffmpeg.input('movie.mp4')

audio_stream = stream.audio
stream = ffmpeg.hflip(stream)

stream = ffmpeg.output(stream, audio_stream, 'output.mp4')
ffmpeg.run(stream)

5. 静止画像や音声を保存する

5-1. 静止画像を保存する

時間で指定する

filter()で縦横比を維持して横幅を800ピクセルにリサイズしてoutput()によりimage.jpg名で保存します

python
time = 10
width = 800
(
    ffmpeg
    .input('movie.mp4', ss=time)
    .filter('scale', width, -1)
    .output('image.jpg', vframes=1)
    .run()
)

フレームを指定する

filter()でフレームを選択して書き出しています

frame_num = 10
(
    ffmpeg
    .input(path)
    .filter('select', 'gte(n,{})'.format(frame_num))
    .output('image.jpg', vframes=1, format='image2', vcodec='mjpeg')
    .overwrite_output()
    .run()
)

5-2. 音声を保存する

wavで保存する

python
stream = ffmpeg.input('movie.mp4')
stream = ffmpeg.output(stream, 'audio.wav', format='wav')
ffmpeg.run(stream)

mp3で保存する

python
stream = ffmpeg.input('movie.mp4')
stream = ffmpeg.output(stream, 'audio.mp3', format='mp3')
ffmpeg.run(stream)

6. 動画をnumpy arrayにする

rawvideoの出力をoutに格納してnumpy.frombuffer()に渡すとnumpy arrayにしてくれます。特に条件を指定しない場合はすべてのフレームを書き出しますので、例えば30fpsの2K動画10秒分を出力すると [300, 1080, 1920, 3] サイズのnumpy arrayが得られます。

python
import numpy as np
import matplotlib.pyplot as plt

height = 1080
width = 1920

out, _ = (
    ffmpeg
    .input(path, ss=0, t=10)
    .output('pipe:', format='rawvideo', pix_fmt='rgb24')
    .run(capture_stdout=True)
)

arr = (
    np
    .frombuffer(out, np.uint8)
    .reshape([-1, height, width, 3])
)

def show_picture(im):
    plt.imshow(im)
    plt.xticks([])
    plt.yticks([])
    plt.show()

print(arr.shape)
show_picture(arr[0])
show_picture(arr[100])
show_picture(arr[200])

7. まとめ

ffmpegのすべての機能が使えるわけではないようですが、手軽に動画の情報を取得したり、動画をnumpy arrayに変換できるのは便利だと思います。

レッツトライ

50
57
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
50
57