Intel入ってるNASでVAAPIを使う

# きっかけ
nasneでTVを観ているのですが，

- 視聴に専用のソフトが必要
- Macで視聴するには，
    - Parallels/VMware Fusionなどのような，高性能な仮想化ソフトウェアを用いてPCTV Plusで視聴しないといけない．
    - 非公式なMac用ソフトウェアが必要．
- そもそもnasneのHDDが死んだときに録画データも死ぬ．当然市販のレコーダーだって同様．
    - 市販の録画機では冗長性0．

などの問題があり，市販のエンドユーザ向け録画機ではまともに利用できません．

そこで，録画サーバを構築しようと思ったのですが，サーバでトランスコード/エンコードができないと，
帯域・ストレージリソースを大量に消費してしまいますよね．
そうなると，HWエンコーダなどの支援がほしいところです．

## NAS
現在，私はSynology DS218+というNASを持っています．
このNASは，IntelのCeleron J3355というCPUが内蔵されています．このため，Synology公式でDockerに対応しています．
また，このCPU，Intel公式を見てみると，**QSV**に対応している模様です．
https://ark.intel.com/content/www/jp/ja/ark/products/95597/intel-celeron-processor-j3355-2m-cache-up-to-2-5-ghz.html
つまり，DockerからうまいことHWエンコーダを呼び出せば，QSVを利用して高速エンコードができるようになります．

# 目的
しかし，やはり実際にエンコードを走らせてみないと，まともに使えるのかわかりません．
そこで，本記事においての目的としては，録画サーバを組む前段階として，
**Intel入ってるNASでは，HWエンコードがどのくらいの性能なのか？**とします．


# 用意したもの
- DS218+
    - おそらくQSV対応のIntel CPUを積んでいて，以下の条件に合致していれば，他のNASでも使えると思います．
    - NASにSSH可能
    - Dockerインストール済み
    - 後述するスクリプト
    - DSMのLinuxカーネル4.4.59+   
      
      ```
      $ uname -r
      4.4.59+
      ```
- 30分アニメを録画したtsファイル(hoge.ts)
- **非公式**なので，何があっても自分でなんとかする強い気持ち

# 検証
IntelCPUが入っている本NASにおいては，encordデバイスが`/dev/dri:/dev/dri`にあります．
他のIntelCPUが内蔵されているものも同様かと思われます．
これをコンテナに渡してやることで，コンテナ内にて，ホストのHWエンコーダを利用できます．

## 方法
こちらを参考にしました．→https://timothybasanov.com/2018/12/08/hardware-accelerated-h264-encoding-synology-nas.html

今回は，VAAPIでQSVを使います．
このため，VAAPIに対応したffmpegなDockerコンテナで検証します．

以下のスクリプトを書きました．

```bash:encord_test.sh
#!/bin/sh
host_tsdir=/volume1/video
container_tsdir=/tmp
host_mp4dir=/volume1/video/mp4
container_mp4dir=/media
movie_name=hoge

sudo docker run --rm \
--device /dev/dri:/dev/dri \
-v ${host_tsdir}:${container_tsdir} \
-v ${host_mp4dir}:${container_mp4dir} \
jrottenberg/ffmpeg:vaapi \
-hwaccel vaapi -hwaccel_output_format vaapi \
-i ${container_tsdir}/${movie_name}.ts \
-vf 'scale_vaapi=w=1280:h=720' \
-c:v h264_vaapi \
${container_mp4dir}/${movie_name}.mp4
```

# 結果
エンコード速度とCPU負荷の検証，エンコード前後でのファイルサイズの比較を行いました．

## 実行速度
まず，スクリプトを実行したときの実行結果です．
4倍以上，安定してエンコードできているのがわかります．非常に高速です．

```
./encord_test.sh
(省略)
Output #0, mp4, to '/media/hoge.mp4':
  Metadata:
    encoder         : Lavf58.20.100
    Stream #0:0: Video: h264 (h264_vaapi) (avc1 / 0x31637661), vaapi_vld, 1280x720 [SAR 1:1 DAR 16:9], q=-1--1, 29.97 fps, 30k tbn, 29.97 tbc
    Metadata:
      encoder         : Lavc58.35.100 h264_vaapi
    Stream #0:1: Audio: aac (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 128 kb/s
    Metadata:
      encoder         : Lavc58.35.100 aac
frame= 1996 fps=142 q=-0.0 size=   42240kB time=00:01:06.46 bitrate=5206.1kbits/s dup=14 drop=0 speed=4.72x
```
## 処理負荷
このとき，どのくらいのCPUリソースを利用しているのかみてみました．
ちなみにリソース監視は，Prometheus+NetData+GrafanaをDockerで建てて，フルコンテナ運用しています．
スクリーンショットはGrafanaのダッシュボードです．
概ね40%ちょっとくらいのCPU使用率で安定しています．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271301/70150468-bb0f-f4d3-2032-a8f3b1e3a6aa.png)

## 圧縮率
今回，1920x1080のtsファイルを，1280x720のmp4(h264)に変換したため，割と小さいサイズになっています．
概ね半分以下のサイズに抑えられています．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271301/7e80ccd7-01bf-5d60-dc1e-4fe1939ae2cd.png)

# まとめ
非常に実用的な速度で，実用的なリソース消費で，消費電力も(おそらく)そこまでではなさそうなので，
IntelのQSVが使えるNASをお持ちであれば，エンコードサーバにするのもありだと思います．
今回，録画サーバにおけるエンコード性能として検証しましたが，systemdで適当に動かすなり，
cronでスケジューリングなりすれば，NASに溜めておいたホームビデオの自動エンコードなども可能になると思います．
また，まだまだffmpegの設定を調整すれば，さらなる容量削減や，インターレース解除などもできると思いますし，
そこあたりは今後の課題とします．いいffmpegオプションなどありましたらぜひ教えて下さい．

## 録画サーバを組むとしたら
チューナデバイスとしては，PX-S1UDを考えています．このチューナ，ドライバがPLEX公式から出ています．
また，Linuxのディストリ依存などがなく，DSMでも動く模様(https://qiita.com/xingoxu/items/c813c4ed048116f653a6#%E3%82%A2%E3%83%B3%E3%83%86%E3%83%8A%E8%A8%AD%E7%BD%AE )です．良かった．
当初は，エンコード性能・省電力性能が高いRaspberry Pi4を買おうか迷っていましたが，NAS一台で完結しそうです．
また，録画サーバのソフトウェア周りも実はコンテナ化して運用可能です．
https://github.com/l3tnun/docker-mirakurun-epgstation 
つまるところ，NAS一台で，録画サーバまでフルコンテナ運用ができそうです．
万一，Docker内サーバの環境が壊れても，別にいくつかのバックアップをちゃんと取るようにしているので，
ある程度の冗長性が確保できそうです．かなり安定性の高い録画システムが組めるのではないでしょうか．


# おまけ
1920x1080で出力した結果がほしいという声が聞こえてきそうなので，検証してみました．

## 実行速度
```
Output #0, mp4, to '/media/hoge.mp4':
  Metadata:
    encoder         : Lavf58.20.100
    Stream #0:0: Video: h264 (h264_vaapi) (avc1 / 0x31637661), vaapi_vld, 1920x1080 [SAR 1:1 DAR 16:9], q=-1--1, 29.97 fps, 30k tbn, 29.97 tbc
    Metadata:
      encoder         : Lavc58.35.100 h264_vaapi
    Stream #0:1: Audio: aac (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 128 kb/s
    Metadata:
      encoder         : Lavc58.35.100 aac
frame=52707 fps= 85 q=-0.0 Lsize= 2034563kB time=00:29:18.59 bitrate=9477.6kbits/s dup=14 drop=0 speed=2.85x
```

## 処理負荷
ダウンコンバートしていないためか，多少，CPU負荷が少なくなっています．概ね40%行かないくらいのCPU使用率ですね．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271301/61d1fc26-3d15-dec3-0c18-c13044633edb.png)


## 圧縮率
ほとんど圧縮できていませんね．でもffmpegの設定をよしなに調整すればちゃんと圧縮できそうです．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271301/54f763f1-5af8-2058-7669-b3455d510415.png)