酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

Raspberry Pi 4 と docker-mirakurun-epgstation で録画サーバーを構築する (2023年2月版)

Raspberry Pi 4 Model B (以下ラズパイと記す)で構築した録画サーバーが死んでいるのに気付かず、3日前の「ローカル路線バス乗り継ぎ対決旅 陣取り合戦」を見逃してしまった。

2年前に「Raspberry Pi 4とdocker-mirakurun-epgstationで録画サーバーを構築する (2021年4月版)」にて録画サーバーを構築する方法を紹介した。前回の録画サーバーの構築から2年も経っており Mirakurun と EPGStation の最新版を利用したかったのもあって録画サーバーを再構築した。

本記事では「Raspberry Pi OS Lite (32bit)」をベースとして録画サーバーを構築する。デスクトップ機能付きの「Raspberry Pi OS Full」を使いたい場合は、本記事に書かれている方法では上手くいかないようなので注意すること。

2023年2月現在ラズパイは高騰しており、当時6,000円で買えたものが 3倍の 18,000円になっており、新規に機材を揃えるのであれば同価格で購入できる Intel CPU なミニPCを買った方が安く済む。今から機材を揃えるのであれば、個人的にはラズパイで録画サーバーを構築するのはあまりオススメしない。

また、本記事ではハードウェアエンコーダー h264_omx の利用は想定していない。2年間運用して分かったことではあるが h264_omx には画質に難があり、リアルタイムにテレビをみない著者としては高画質の x264 の方が嬉しかった。h264_omx の利用したい場合には 2021年4月版の記事を参照していただきたい。

上から順番に実施していくと録画サーバーが構築できるようになっている。ラスパイの楽しいところは環境を破壊しても5分あれば再構築が可能なところである。何度も壊して遊ぼう!

使用機材

録画サーバーを構築するにあたって購入した機材は以下の通り。

本記事で紹介するのは「Raspberry Pi OS 32bit」での運用方法についてなので4GBで十分だと判断した。

PX-S1UDも2台までであればラズパイのバスパワーで動作することを確認している。ただし安定稼働させたかったので後述のUSBハブを利用することにした。

Aliexpressで「vastdtv」で検索すると同等品を購入することができるらしい。3,000円ほどなので届くまでに1ヶ月ほど待てるのであればAliexpressで購入するのもアリかもしれない。プリペイド式クレカサービスの Revolut を使うと為替レートが最小で済むので個人的にオススメしたい。

当初は外付けSSDを使っておりその時は安定稼働していたが、この外付けHDDに変えた途端に不安定になってしまった。2.5インチHDDなら電力消費量も低いので大丈夫だと考えたが外部から給電が必要なようだ。外付けHDDとチューナーデバイス系はすべてセルフパワーのUSBハブに繋げることにした。

UGREENのUSBハブはセルフパワー対応に加え、逆流防止機能付きだったのが採用の決め手となった。

この充電器は合計出力が60Wある。一系統はラズパイ本体用、もう一系統はUSBハブへの給電用に使っている。

NTT-Com SCR3310のOEM品を新品で購入することができる。メルカリの相場だと1,500円くらいで販売されている。過去には 500円くらいで売られていたこともあるが、本記事の執筆時点では確定申告の時期と被っているので中古でも値段が上がっているのかもしれない。

Raspberry Pi OS Lite のインストール

ラズパイはmicroSDに書き込まれたOSで動く。

Raspberry Pi Imager を使うと指定した設定とOSを書き込んでくれる。Raspberry Pi Imagerを公式ページからダウンロードできる。2023年2月時点では v1.7.3 が最新となっている。

Raspberry Pi Imagerを起動して[CHOOSE OS]ボタンをクリックする。デスクトップ機能は不要なので「Raspberry Pi OS (other)」から「Raspberry Pi OS Lite (32bit)」を選択する。

Command + Shift + X を同時に押すと Advanced options が表示される。[Enable SSH]を有効にして、pi userのパスワードを入力する。ここはあとあとの説明と合わせるために「raspberry」としておく。

[Configure wifi]を有効にする。自宅のWi-FiのSSIDとパスワードを入力する。Wifi countryを JP に設定しておく。

これでラズパイが起動後に即時Wi-Fi接続するので有線LANに繋げて作業する必要がなくなる。もちろんssh接続もできる。

あとは適切なmicroSDカードを選択して、[WRITE]ボタンをクリックするだけである。

[WRITE]ボタンをクリックすると書き込みが開始する。Lite版なので容量も少なく10分もせずに書き込みは完了する。最初の1回目はOSをダウンロードするため少し時間がかかる。

ローカルPCとラズパイの疎通確認

初回起動時は起動まで2〜3分かかる。電源投入から少し待ってから疎通確認をする。ネットワーク内にラズパイが1台だけだった場合は raspberrypi.local で接続できる。これは超便利。

ssh pi@raspberrypi.local

Raspberry Pi Imagerで設定したパスワードは raspberry を入力するとログインできる。

$ ssh pi@raspberrypi.local
The authenticity of host 'raspberrypi.local' can't be established.

... (中略)

pi@raspberrypi:~ $ 

ラズパイの設定:ライブラリのアップデート

ラスパイに初期導入されているライブラリをアップデートする。

sudo timedatectl set-timezone 'Asia/Tokyo'
sudo localectl set-locale 'LANG=ja_JP.UTF-8'
sudo apt update && sudo apt upgrade -y && sudo apt install locales-all

ラズパイの設定:ネットワークに接続してからブートさせる

通常はラズパイが起動してからネットワーク接続する流れだが、NASのドライブをマウントしている場合などはネットワークに接続してから起動して欲しい。

sudo raspi-config

[System Options]を選択する。

[Network at Boot]を選択して、ネットワーク接続後にブートするように設定する。

ラズパイの設定:Vimのインストール (Optional)

ラズパイには vim-tiny が標準でインストールされているが、さくさんは vim を使うのでアンインストールする。

sudo apt --purge remove vim-common vim-tiny -y
sudo apt install vim -y

ラズパイの設定:スワップの無効化

microSDを保護するため、スワップによるアクセスを最小化させる。

sudo swapoff --all
sudo apt remove dphys-swapfile -y
sudo sed -i 's/$/ coherent_pool=4M dwc_otg.host_rx_fifo_size=2048/' /boot/cmdline.txt
sudo sed -i 's/^CONF_SWAPSIZE=100/CONF_SWAPSIZE=1024/' /etc/dphys-swapfile
sudo apt autoremove

ラズパイの設定:ログの最小化

microSDを保護するため、ログによるアクセスを最小化させる。

sudo vim /etc/rsyslog.conf

rsyslog.conf を編集して下記を参考にしてコメントアウトする。

###############
#### RULES ####
###############

#
# First some standard log files.  Log by facility.
#
auth,authpriv.*                 /var/log/auth.log
*.*;auth,authpriv.none          -/var/log/syslog
#cron.*                         /var/log/cron.log
#daemon.*                        -/var/log/daemon.log
#kern.*                          -/var/log/kern.log
#lpr.*                           -/var/log/lpr.log
#mail.*                          -/var/log/mail.log
#user.*                          -/var/log/user.log

PX-S1UD V2.0 チューナーのドライバのインストール

地上波チューナーとして「PX-S1UD」を採用している。

ドライバをインストールする。

wget http://plex-net.co.jp/plex/px-s1ud/PX-S1UD_driver_Ver.1.0.1.zip
unzip PX-S1UD_driver_Ver.1.0.1.zip
sudo cp PX-S1UD_driver_Ver.1.0.1/x64/amd64/isdbt_rio.inp /lib/firmware/
rm PX-S1UD_driver_Ver.1.0.1.zip
rm -rf PX-S1UD_driver_Ver.1.0.1

下記のコマンドでチューナーデバイスが正しく認識しているかどうか確認することができる。

$ dmesg | grep PX-S1UD
[    2.505280] usb 1-1.2: Product: PX-S1UD Digital TV Tuner
[    2.735291] usb 1-1.3: Product: PX-S1UD Digital TV Tuner

Raspberry Pi OS にはチューナードライバが標準で入っているので、PX-S1UDドライバをインストールしなくても良いはずだが、ドライバをインストールしないと Mirakurun で電波の受信ができない問題があった。原因は不明だがドライバをインストールしたところ解決した。当時のログを念のため貼っておく。

2023-02-25T20:31:16.887+09:00 info: TunerDevice#0 process has spawned by command `dvbv5-zap -a 0 -c ./config/dvbconf-for-isdb/conf/dvbv5_channels_isdbt.conf -r -P 21` (pid=267)
2023-02-25T20:31:16.894+09:00 debug: TunerDevice#0 > using demux 'dvb0.demux0'
reading channels from file './config/dvbconf-for-isdb/conf/dvbv5_channels_isdbt.conf'
ERROR    Device or resource busy while opening /dev/dvb/adapter0/frontend0
2023-02-25T20:31:16.896+09:00 debug: TunerDevice#0 cat process has closed with code=1 by signal `null` (pid=268)
2023-02-25T20:31:16.897+09:00 info: TunerDevice#0 process has closed with exit code=255 by signal `null` (pid=267)
2023-02-25T20:31:17.898+09:00 warn: TunerDevice#0 respawning because request has not closed

ラズパイの設定:外付けHDDの設定をマウントする

録画したデータは外付けHDDに保存する。すでに外付けHDDをUSB接続しているので、ラズパイでHDDが接続されていることを認識しているか調べる。

$sudo fdisk -l

(中略)

Device      Start        End    Sectors  Size Type
/dev/sda1      40     409639     409600  200M EFI System
/dev/sda2  411648 3907028991 3906617344  1.8T Microsoft basic data

外付けHDDは /dev/sda2 として認識されていることがわかったのでマウントする。

sudo mkfs.ext4 /dev/sda2
sudo mkdir /data
sudo mount /dev/sda2 /data

さらにffmpegを使ってエンコードする際に支障がでないように、ユーザーが /data にアクセスできるように変更しておく。

sudo chown 1000:1000 /data

起動時に外付けHDDを自動マウントさせる

ラズパイの起動時に外付けHDDが自動でマウントさせるように設定する。まずは /dev/sda2 の UUID または PARTUUID を調べる。

$ sudo blkid /dev/sda2
/dev/sda2: UUID="82d9561e-7af8-4b7c-9d5e-fb153b102b46" TYPE="ext4" PARTUUID="66fbea03-9b65-4b0b-9928-cc4d6698c230"

/dev/sda2のPARTUUIDがわかった。

sudo vim /etc/fstab

下記を参考に fstab を編集する。

PARTUUID="66fbea03-9b65-4b0b-9928-cc4d6698c230" /data           ext4    defaults,nofail 0 0

ラズパイを再起動して、再度きちんとマウントされるか確認する。

sudo reboot

再起動後に df コマンドで、/data に対してきちんとHDDが割り当てられているか確認すること。供給電力が低下すると外付けHDDが勝手に接続解除されていることがあり、HDD への書き込みのつもりが知らない間に microSD へ書き込んでることもあり得るため、定期的にチェックした方がよい。

$ df
ファイルシス   1K-ブロック    使用     使用可 使用% マウント位置
/dev/root         57986488 4262912   51336036    8% /
devtmpfs           1800660       0    1800660    0% /dev
tmpfs              1965524       0    1965524    0% /dev/shm
tmpfs               786212    1408     784804    1% /run
tmpfs                 5120       4       5116    1% /run/lock
/dev/sda1       1921724608    4520 1824028032    1% /data
/dev/mmcblk0p1      261108   51034     210074   20% /boot
tmpfs               393104       0     393104    0% /run/user/1000

git と Docker と docker-compose のインストール

git と Docker と docker-compose をインストールする。

$ sudo apt install -y git docker docker-compose
$ docker -v
Docker version 20.10.5+dfsg1, build 55c4c88
$ docker-compose -v
docker-compose version 1.25.0, build unknown

インストールが完了したらDockerを起こしておく。

sudo systemctl enable docker

再起動もしておく。

sudo reboot

docker-mirakurun-epgstation のインストール

今回は forkしてカスタムしたリポジトリではなく、新バージョンに追従しやすいように docker-mirakurun-epgstation をそのまま使うことにする。基本的にそのままでいけるが、データベースはラズパイ用のものに変更しておく必要があった。順番に説明していく。

cd /data
curl -sf https://raw.githubusercontent.com/l3tnun/docker-mirakurun-epgstation/v2/setup.sh | sudo sh -s

docker-mirakurun-epgstation 起動前に /data ディレクトリの owner の確認

EPGStation では ffmpeg を使ってエンコードが実施される。このとき、video ユーザーによってエンコードがおこなわれる。/data ディレクトリ の owner が root だった場合、ffmpeg が動画データを出力できなくなってしまう。

sudo chown -R 1000:1000 /data

きちんと変更できたか確認しておく。

$ sudo ls /data -la

drwxr-xr-x  3 pi   pi   4096  226 15:56 .
drwxr-xr-x 19 root root 4096  226 15:49 ..
drwxr-xr-x  7 pi   pi   4096  226 15:56 docker-mirakurun-epgstation

arm32用の mariadb がないので alpine-mariadb を利用する

ラズパイでは mariadb が使えないようでこのままsudo docker-compose up -d を実行するとエラーが発生する。利用するデータベースを mariadb:10.5 から yobasystems/alpine-mariadb:10.5 へ変更する。

cd /data/docker-mirakurun-epgstation
vim docker-compose.yml

mysqlのイメージ名を書き換えた。

  db:
    image: yobasystems/alpine-mariadb:10.5

さらに Mirakurun 3.9.0-rc.2 とラズパイの相性が悪いのか予約録画ができなくなっていたので、順番にダウングレードしていって安定している 3.8.0 で固定した。

  mirakurun:
    image: chinachu/mirakurun:3.8.0

config.yml の変更 (Optional)

EPGStation デフォルトのファイル名は '%YEAR%年%MONTH%月%DAY%日%HOUR%時%MIN%分%SEC%秒-%TITLE%' となっている。冗長と感じたため '%YEAR%%MONTH%%DAY%-%TITLE%'へ変更する。

cd /data/docker-mirakurun-epgstation/epgstation/config
vim config.yml 

recordedFormat を任意のフォーマットに変更する。

recordedFormat: '%YEAR%%MONTH%%DAY%-%TITLE%'
recordedFileExtension: .m2ts

Docker をビルドして起動させる

docker-composeを使ってビルドを開始する。

cd /data/docker-mirakurun-epgstation
sudo docker-compose up -d

問題なければ約20分でビルドが完了して、MirakurunとEPGStationが起動する。

Mirakurunのチャンネルスキャン

放置しておけば Mirakurun が勝手にチャンネルをスキャンしてくれるが、たまに特定のチャンネルが抜けることがあるので、一度は明示的に呼んでおいた方がよいかもしれない。

curl -X PUT "http://raspberrypi.local:40772/api/config/channels/scan"

チャンネルスキャン後にラズパイを再起動して1時間くらい待てば、EPGStationで番組表が観られる状態になっている。

以上で録画サーバーの構築方法は終了だ。

トラブルシューティング:長期間稼働していると無線LAN経由で epgstation や ssh に接続できなくなる

長期間ラズパイを動かしていると Wi-Fi に接続できなくなってしまう。解決できなかったので有線LANで運用することにした。

トラブルシューティング:長期間稼働していると PX-S1UD が認識しなくなる

長期間ラズパイを動かしていてもラズパイ自身は問題なく稼働しているが、チューナーデバイスが死んでしまう現象が1週間に1回は発生していた。再起動すれば治るのだが原因が特定できず 2年が経った。

チューナーデバイスを動かす電力はラズパイ本体から直接取っていたため、なんらかのタイミングで給電容量が下がってしまいチューナーが落ちてしまったのではないかと考えた。

今回の構成では、外付けHDD、カードリーダー、チューナーのすべてをセルフパワー対応のUSBハブ経由にすることで給電容量が落ちなくすることを想定している。こちらの検証結果については後日まとめたいと思う。

Tips: ラズパイからNASへ差分ファイルのみをコピーする

我が家ではラズパイに余計な負荷を掛けないように、NASへ録画したデータを転送して、NASのDLNAサーバー経由で動画を観ている。ラズパイからNASへ差分ファイルのみを転送する方法を紹介した。

ラズパイ側はいつでも壊れても(壊しても)良いようにこまめにバックアップするようにしたい。