ffmpeg-pythonで動画編集する

# 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
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/4b34d399-8a3c-bb11-38b0-ccecca54f757.png" width=30%>
落としてきた圧縮ファイルを適当なフォルダに展開して、binフォルダにPATHを通せばインストール完了です
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/277233/34f968b2-b473-32d4-b0a7-9ff5298d1cfc.png)
PATHが通ってれば以下のようにterminalから呼べるようになっている筈です

```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:terminal
pip install ffmpeg-python
```


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


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


```python: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:python
stream = ffmpeg.input('movie.mp4')
stream = ffmpeg.hflip(stream)
stream = ffmpeg.output(stream, 'output.mp4')
ffmpeg.run(stream)
```


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


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


# 4. 動画を加工する


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


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


```python:読み込みで範囲指定
stream = ffmpeg.input('./movie.mp4', ss=2, t=2)
```

```python:書き出しで範囲指定
stream = ffmpeg.output(stream, 'output.mp4', ss=2, t=2)
```


## 4-2. 画像を反転する


```python:左右反転
stream = ffmpeg.hflip(stream)
```


```python:上下反転
stream = ffmpeg.vflip(stream)
```


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


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


```python: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: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:python
stream = ffmpeg.input('movie.mp4')
stream = ffmpeg.output(stream, 'audio.wav', format='wav')
ffmpeg.run(stream)
```


## mp3で保存する


```python: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: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に変換できるのは便利だと思います。

レッツトライ