TV録画 環境構築メモ (WindowsServer2016 + PX-W3PE4 + Mirakurun)

# 概要
今までWindowsServer2016のサーバーにHyper-Vで立ち上げたUbuntu18.04でTV環境を構築していた。
サーバー再起動時にチューナーを認識しなくなる不具合が何度もあり、WindowsServer2016にTV環境を移してみることに。
環境構築方法をメモ代わりに残しておく。

# 過去の環境
サーバーOSにはWindowsServer2016を使いたい。
Hyper-Vで起動したUbuntuを立ち上げ、その上でMirakurunでチューナーを仮想化してクライアントはChinachuを利用していた。
具体的には、PCIE-USBインターフェースボードにTVチューナーをつなげて、Hyper-V DDAで仮想マシンに直接ボードをマウントする運用だった。
ただ、再起動するとチューナーを認識しないことがあり不安定だった。

# 環境構築
## チューナーとカードリーダー
- PX-W3PE4
- ACR39U
## ドライバ
まず、販売元のドライバは安定しない過去があったので使わない。
以下の素敵なレポジトリにあるものを使わせていただく。
https://github.com/nns779/px4_drv
### Visual Studioのインストール
バージョンは最新なら何でも良いと思う。
今回は2022を使用する。
### ドライバの前準備
1. レポジトリをクローンするかgithubからダウンロードする。
2. `winusb/px4_winusb.sln`をVisualStudioで開き、ソリューションをRelease構成でリビルドする。
    - `winusb/build/x64/Release`にビルド結果が生成される
3. `winusb/build/x64/Release/`に`px4_drv/fwtool/fwinfo.tsv`をコピーする。
4. 販売元からドライバをダウンロードする。
    - このとき、`fwinfo.tsv`に記載のあるドライバを選択するようにする。
    - ファイルサイズやCRCを見る。
5. `./fwtool PXW3PE4.sys it930x-firmware.bin`を実行する。
    - `it930x-firmware.bin`が生成される。
### ドライバのインストール
1. Windowsのテスト署名されたドライバに関する設定を解除する。
    - `Bcdedit.exe -set TESTSIGNING OFF`を実行する。
    - `msinfo32.exe`で`セキュアブート`が有効になっていれば、UEFIからSecureBootを無効にする。
    - `Shift+再起動ボタン`でスタートアップ設定を変える準備をして、`ドライバ署名の強制の無効化`を選択してWindowsを起動する。
2. デバイスマネージャーから`PX-W3PE4`を右クリックしてドライバのインストールを行う。手動で選択し、`winusb/pkg/inf`を指定する。
    - `インストールする`の方を選んでクリックする。
### BonDriverの準備
BonDriverのファイルを集めておく。あとでMirakurunの設定で使う。
- `px4_drv\winusb\pkg\BonDriver_PX4`からすべてのファイルをコピー。
- `px4_drv\winusb\pkg\DriverHost_PX4`からもすべてのファイルをコピー。
- `winusb/build/x64/Release/`からは`DriverHost_PX4.exe`と`BonDriver_PX4.dll`と`it930x-firmware.bin`の3つをコピー。
- `BonDriver_PX4.dll`に関しては、`-S`と`-T`の分を作成する。
- 設定ファイルが読み出せなくなるため、`_S`などの間違いに注意。

## Mirakurun
### インストール
1. `Node.js 14.17.0 (x64)`をダウンロードしてインストールする。
2. 以下のコマンドをPowerShellで実行する。

    ```
    npm install winser@1.0.3 -g
    npm install mirakurun@latest -g --foreground-scripts --production
    ```
3. `http://localhost:40772/`を開いてMirakurunが起動していることを確認する
### 設定
1. BonRecTestをダウンロードする。
    - https://github.com/rndomhack/BonRecTest/releases
1. BonDriverのファイル群と同じフォルダに、`x64/BonRecTest.exe`をコピーする。
1. 以下をクローンしビルドして、`x64/Release/`の`libaribb25.dll`と`arib-b25-stream-test.exe`をコピーする。
    - https://github.com/tsukumijima/libaribb25
1. MirakurunのUIで`Config`->`Tuners`->`Add Tuner`から以下のように追加する。`-T0`, `-T1`, `-S0`, `-S1`の4つ分を登録する。
    - Commands: `BonRecTest.exe --driver BonDriver_PX4-T.dll --output - --channel <channel> `
    - DVB Device Path: 空
    - Decoder: `arib-b25-stream-test.exe`
1. Windowsのファイアウォール設定の例外に追加する。
    - 必要に応じてMirakurunのポート番号を変える。
    - ファイアウォールのリモートIPも適宜設定する。
1. 他のLinuxから以下を実行して、チャンネルスキャンを実行する。

    ```
    curl -X PUT "http://<WindowsServer IP>:40772/api/config/channels/scan?type=GR&setDisabledOnAdd=false&refresh=true"
    curl -X PUT "http://<WindowsServer IP>:40772/api/config/channels/scan?type=BS&setDisabledOnAdd=false&refresh=true"
    curl -X PUT "http://<WindowsServer IP>:40772/api/config/channels/scan?type=CS&setDisabledOnAdd=false&refresh=true"
    ```

### BSチャンネル設定(手動)
Mirakurunの自動チャンネルスキャンでは、px4_driverとBonRecTestの組み合わせではBS/CSは正しくスキャンできない様子。
原因は、`BonRecTest`と`px4_driver`は`channel`に番号を指定することを想定して作られているため。
- https://github.com/rndomhack/BonRecTest/blob/5bb99b983b90dbd4d256c26cc9772b99d8016899/BonRecTest/Main.cpp#L69
- https://github.com/nns779/px4_drv/blob/7fa9f05d2cbdf1d821f479248d561f9868051b8b/winusb/src/BonDriver_PX4/chset.cpp#L157)

`px4_driver`では`BonDriver_PX4-S.ChSet.txt`で定義された順に`channel`番号が割り振られており、例えば`channel=0`を指定すると`BS001/TS0`が選択される。
解決方法としては、以下の2つかなと思う。
1. `BonRecTest`がMirakurun(recpt1準拠?)の`BS01_0`のような表記をパースできるようにする。
    - Mirakurunのチャンネルスキャンでは`BS01_0`から`BS23_3`のすべてをスキャンするようになっている
        - https://github.com/Chinachu/Mirakurun/blob/a172685046c13f9d5ab9e4c7fd189696b0bfa792/src/Mirakurun/api/config/channels/scan.ts#L93
    - `BS<chid>_<tsid>`が与えられたとき、`<chid>*4 + <tsid>`を計算し`channel`argumentとして受け入れるようにする
    - 正確な`BS01_0`と`channel`の対応関係は取れなくなるが、動作は問題ないはず。
    - 具体的にはBonRecTestの`Main.cpp`を以下のように変更した、
        - `GR`も同様にずれるので`-13`している。魔改造すぎる
    ```
    //commit hash = 5bb99b983b90dbd4d256c26cc9772b99d8016899
    int _tmain(int argc, TCHAR* argv[])
    {
        ...
		}
		else if (!_tcscmp(argv[i], TEXT("--channel"))) {
			DWORD channel;
			if (argv[i + 1][0] == 'B' && argv[i + 1][1] == 'S')
			{
				channel = _tcstoul(argv[i + 1]+2, &pEnd, 10);
				DWORD streamid = _tcstoul(argv[i + 1]+2+3, &pEnd, 10);
				channel = (channel - 1) * 4 + streamid;
				std::cerr << " fed BS channel...recognize as channel=" << channel << std::endl;
			}
			else
			{
				channel = _tcstoul(argv[i + 1], &pEnd, 10) - 13;
			}
        ...
    }
    ```
2. 自分でMirakurunの`tuners.yml`を書く。
    - その際は、`channel`に直接番号を書く。

## EPGStationかなにかを導入する
これから