NVEncを利用したEPGStationのハードウェアエンコード環境

# これまでの録画環境と変更点
以前はIntel の内蔵GPU(iGPU)のVAAPIを利用していたのですが、GPUの追加(RTX2060)に伴いNVEncを利用したエンコード設定に変更しました。設定にあたってはEPGStationのDockerイメージ内にffmpegをインストールするのが一般的ですが、手順やビルドが非常に煩雑なため、NVEncが付属したffmpegコマンドが実行できるDockerイメージを作り、EPGStationからDockerコマンドで実行するような方針で構成してみました。
5ヶ月経過現在、エンコード時400FPS・GPU使用率15%・CPU使用率1%くらいの運用で安定しています。


> **ミドルウェア**
OS ubuntu20.04
docker 19.03.8
docker-compose 1.26.0
nvidia-docker 2.5.0
NVIDIA-SMI 460.73.01 / Driver Version: 460.73.01 / CUDA Version: 11.2  
**ハードウェア**
M/B PRIME H310M-E R2.0 
GPU RTX2060
CPU i7-9700F

**設定にあたっての前提**
Dockerコマンド、docker-composeコマンド、nvidia-dockerコマンドが利用できること、[Docker-mirakurun-EPGStation](https://github.com/l3tnun/docker-mirakurun-epgstation)を利用していること


:::note
2021/10/16　追記
最近、旧手順でビルドしなおしたところ、以下のようなエラーが出て困ったため、より簡単な手順を追記しました。古い手順は自身でビルドしたい方向けに記事の最後におまけとして残していますので必要に応じて参考にしてください。
 > Driver does not support the required nvenc API version. Required: 11.1 Found: 11.0
:::

# 設定方法
epgstationサービス内からDockerコマンドが扱えるように、docker-compose.ymlファイルに以下１行を追記します。`#追加`のコメント箇所が追加した行です。

```docker-compose.yml
    epgstation:
        build: epgstation
        volumes:
            - /etc/localtime:/etc/localtime:ro
            - ./epgstation/config:/app/config
            - ./epgstation/data:/app/data
            - ./epgstation/thumbnail:/app/thumbnail
            - ./epgstation/logs:/app/logs
            - ./recorded:/app/recorded
            - /var/run/docker.sock:/var/run/docker.sock # 追加
        environment:
            TZ: "Asia/Tokyo"
        depends_on:
            - mirakurun
            - mysql
        ports:
            - "8888:8888"
            - "8889:8889"
        restart: always
        privileged: true # 追加

```

エンコードスクリプトを追加します。以下のファイルをepgstation/configのディレクトリに作成します。スクリプト中、`<ホスト側録画ディレクトリ>`と書いてある箇所にはコンテナ内/app/recordedのホスト側ディレクトリの絶対パスを指定してください。上のdocker-compose.ymlの設定だと、`<docker-compose.ymlの絶対ディレクトリ>/recorded` になるでしょう。

```epgstation/config/enc_nvenc.sh
#!/bin/bash

img=jrottenberg/ffmpeg:4.3-nvidia1804
ffmpeg_cmd="docker run --rm --gpus all -u`id -u`:`id -g` -v <ホスト側録画ディレクトリ>:/app/recorded $img"
$ffmpeg_cmd -c:v mpeg2_cuvid -deint adaptive -drop_second_field 1 -i "$INPUT" -c:v h264_nvenc -vb 3M -rc vbr_hq -c:a aac -b:a 192k -r:a 48000 -ac 2 "$OUTPUT"
```

最後にエンコードオプションを追加します。`#追加`コメントは誤動作の原因になるので消しておいてください。

```epgstation/config/config.yml
# 省略
encode:
    - name: H.264
      cmd: '%NODE% %ROOT%/config/enc.js'
      suffix: .mp4
      rate: 4.0
    - name: H264/nvenc                            # 追加
      cmd: /bin/bash %ROOT%/config/enc_nvenc.sh   # 追加
      suffix: .mp4                                # 追加
```




# 動作確認

EPGStationを開き、オプションが表示されていればエンコードしてみましょう。多分問題なく動作すると思います。
![Screen Shot 2021-05-01 at 15.12.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96637/8cab4ba4-7eb3-ff7d-bc66-eae659576c25.png)


# 参考
https://qiita.com/yamakenjp/items/7474f210efd82bb28490

https://githubmemory.com/repo/jrottenberg/ffmpeg/issues/317

# おまけ（自分でビルドする場合)
:::note warn
本手順は非推奨です
:::

nvcc付属のffmpegのDockerfileを提供してくれている方がいるのでまずは雛形としてダウンロードします。Docker-mirakurun-EPGStationのdocker-compose.ymlと同じディレクトリで以下のコマンドを実行しリポジトリをクローンしてきます。

```bash
git clone https://github.com/myoshimi/ffmpeg-nvenc.git
```

epgstationサービス内からDockerコマンドが扱えるように、docker-compose.ymlファイルを以下のように修正します。`#追加`のコメント箇所が追加した行です。

```docker-compose.yml
    ffmpeg-nvenc:              # 追加
         build: ffmpeg-nvenc   # 追加
         image: ffmpeg-nvenc   # 追加
    epgstation:
        build: epgstation
        volumes:
            - /etc/localtime:/etc/localtime:ro
            - ./epgstation/config:/app/config
            - ./epgstation/data:/app/data
            - ./epgstation/thumbnail:/app/thumbnail
            - ./epgstation/logs:/app/logs
            - ./recorded:/app/recorded
            - /var/run/docker.sock:/var/run/docker.sock # 追加
        environment:
            TZ: "Asia/Tokyo"
        depends_on:
            - mirakurun
            - mysql
        ports:
            - "8888:8888"
            - "8889:8889"
        restart: always
        privileged: true # 追加

```

エンコードスクリプトを追加します。以下のファイルをepgstation/configのディレクトリに作成します。スクリプト中、`<ホスト側録画ディレクトリ>`と書いてある箇所にはコンテナ内/app/recordedのホスト側ディレクトリの絶対パスを指定してください。上のdocker-compose.ymlの設定だと、`<docker-compose.ymlの絶対ディレクトリ>/recorded` になるでしょう。

```epgstation/config/enc_nvenc.sh
#!/bin/bash

img=ffmpeg-nvenc
ffmpeg_cmd="docker run --rm --gpus all -u`id -u`:`id -g` -v <ホスト側録画ディレクトリ>:/app/recorded $img"
$ffmpeg_cmd -c:v mpeg2_cuvid -deint adaptive -drop_second_field 1 -i "$INPUT" -c:v h264_nvenc -vb 3M -rc vbr_hq -c:a aac -b:a 192k -r:a 48000 -ac 2 "$OUTPUT"
```

最後にエンコードオプションを追加します。`#追加`コメントは誤動作の原因になるので消しておいてください。

```epgstation/config/config.yml
# 省略
encode:
    - name: H.264
      cmd: '%NODE% %ROOT%/config/enc.js'
      suffix: .mp4
      rate: 4.0
    - name: H264/nvenc                            # 追加
      cmd: /bin/bash %ROOT%/config/enc_nvenc.sh   # 追加
      suffix: .mp4                                # 追加
```

コンテナを再起動しておきます。この時にffmpeg-nvencのビルドが走るはずです。

```bash
docker-compose down
docker-compose up -d
```