Ubuntu 18.04 on WSL2によってNVENC(CUDA)を使おうとしてみた結果

　結論から言うと（まだ）出来ませんでした。
　ここでは、今回やろうとしたこと（動画のエンコード）とその結果を残します。

　なお、私の環境は以下の通りです（今年に入って新しくしました）。
　　Windows10 Pro Insider Preview Build 21292
　　Intel Core i7-10750H 2.60GHz
　　NVIDIA GeForece RTX 2060 with Max-Q
　また、WSL2上のLinux DistroはUbuntu 18.04 LTSです。

## 概要
　最近公私ともに動画データが溜まってきており、容量の大きさから保存に難儀していたので一括して圧縮しようと思ったことがきっかけです。
　私はWSL2上のUbuntu 18.04で学習することが多いので、この上でこの課題を解決することを考えました。Ubuntuで簡易な動画編集といえばffmpegがあるので、これを使います。

## GPUを使わないやり方（これはちゃんと動作します）
　まずはffmpeg等をインストールします（私の場合、nasm, yasmがないとNVENCを使おうとする時にエラーが出ましたが、片方だけでも良いのかもしれません）。また、他にも必要なライブラリがあるかもしれません。

```bash:ffmpeg等をインストール
 sudo apt-get install ffmpeg nasm yasm
```
　カレントディレクトリに保存している全ての.MOVの動画を一括してmp4にエンコードして圧縮するコマンドを用意しました。

```bash:動画変換
 for i in *.MOV; do ffmpeg -i "$i" -crf 30 -vf scale=1280:-1 "${i%.*}_c.mp4"; done
```
　○○.MOVのファイル名を`i`に格納し、`ffmpeg`でそのファイルに対して固定品質（`-crf`）で圧縮率30で圧縮、縦サイズのpixel数を1280に固定（`-vf`）し、iから拡張子を除いて○○\_c.mp4になるようにしています。
　なお、\_cは無くてもよいですが、mp4→mp4で圧縮だけしたい時は同名ファイルになってしまうので敢えてつけています。
　また、`-vf`はアスペクト比を固定するので縦動画が紛れている場合は工夫が必要です（そもそもこのオプションを消しても良いと思います）。`-crf`は30だと若干粗くなるので好みによって変えてください。
　ffmpegのオプションは色々なリファレンスがあるのでここでは詳細を割愛します。 

　私の環境ではおよそx1.00 ~ x2.00程度の速度（mp4→mp4ならx5.00程度）で圧縮が始まり、動画が多いとどうしても膨大な時間がかかってしまうので、「GPUが使えたら速くできるのでは？」と思い、最近では以下の通りWSL2上でもハードウェアアクセスが出来るようになっていたので、これを試してみました。

## CUDA Toolkitのインストール
　これは[NVIDIA佐々木さんの記事](https://qiita.com/ksasaki/items/ee864abd74f95fea1efa)がとても分かりやすいので、その通りにやれば出来ます。
　当然のことですが、私の環境（[Build 21292](https://blogs.windows.com/windows-insider/2021/01/13/announcing-windows-10-insider-preview-build-21292/)）でもCUDAは正常に動作しました。
　（余談ですが、私は良く訓練されていないWindowsユーザーなので、Insider Programのベータチャンネルに参加していました（笑）。今回devチャンネルに参加し、21292にしています（が、小心者なので頻繁にアップデートする勇気はないです））

## NVENCを試そうとした結果
　NVENCを使うコマンドは以下となります。「-vcodec h264_nvenc」を追加しています。

```bash:動画変換（GPU）
 for i in *.MOV; do ffmpeg -i "$i" -crf 30 -vf scale=1280:-1 -vcodec h264_nvenc "${i%.*}_c.mp4"; done
```
　しかし、実行すると以下のようなエラーを吐いてしまいます。

```bash:動画変換
 Cannot load libnvidia-encode.so.1
 [h264_nvenc @ 0x55acf1093f40] The minimum required Nvidia driver for nvenc is 378.13 or newer
 Error initializing output stream 0:0 -- Error while opening encoder for output stream #0:0 - maybe 
 incorrect parameters such as bit_rate, rate, width or height
```
　エンコードに必要な`libnvidia-encode.so.1`が読み込めないというエラーです。
　試しにCUDA関連のライブラリが入っているフォルダを含めて検索してみましたがやはり見つかりません。

```bash:ファイルを探してみる
 ~$ find /usr/local/cuda/ -name libnvidia-encode.so.1
 ~$
```

　色々調べてみたところ、NVIDIAのフォーラムに[ほぼ同じ問題に関する記事（2020.9）](https://forums.developer.nvidia.com/t/building-ffmpeg-with-nvenc-inside-docker-container-in-wsl-2-linux-distro/155102/3)がありました（WSL2上のDockerからハードウェアアクセスを試そうとしたものですが）。
　そこでは、以下のように書かれておりencoding/decodingは将来的に解決されるものと理解しました。
> Yes, support for encoding/decoding in WSL2 is coming in a future driver. It was confirmed in the WSLConf’s CUDA session.

　CUDAはDeep Learningファーストで進められていると思っており時間がかかるかもしれませんので、しばらくはCPUに頑張ってもらおうと思います。

## 感想
　CUDA on WSL2はまだNVIDIA Management Library (NVML) API は未実装であるなど、制限事項も多いようです。
　ただし、tensorflow-gpuなどDeep Learning向けの用途では使えるようになったとのことで、いずれエンコード等にも対応するといいなと首を長くして待とうと思います。
　まずは、CUDA本来（？）の用途であるDeep Learningについての学習を続けていきます（今Open AI Gymで遊んでいるのですが、良いアウトプットが思いつかずすぐに寄り道してしまいます……。）

　また、余談ですが私はこういう開発環境等で何が一般的（？）に使われているのかよく分かっていません。WSL2上のlinux distroからdockerを使ってNGCコンテナを利用するのが一つのあり方かなぁとも思いながら、結局自分はWSL2内に色々詰め込んでいます。（他にもいっそMacを使うとか、Linuxを直接使うとかがあるのかなぁとも思いつつ。）
　とはいえ、なんだかんだWindows必須な環境で生きている身としてはWSL2非常に気に入っています（まだ不安定だったり、ベンチマークの結果がベストではないというのは当然ありますが）。
　私は以前cygwinを使ってwindows上にLinuxライクの環境を作っていましたが、cygwinのパッケージ管理をするapt-cygがやはり個人的に好きになりきれませんでした。例えば、ffmpegなどはソースコードからビルドしてインストールする必要がある上、いざやろうとすると必要なパッケージが足りていなくてそのパッケージを入れるにも同様に……。となかなか虚無になっていました。
　この辺りも、情報収集しつつ時代についていきたいです。