ビデオデッキが誕生して何年経つのでしょうか。
その間、VHSとベータの戦争があり、DVDが誕生し、BlueRayやHDDレコーダーへと進化を遂げ続けたTV録画環境
ついに最終話を迎えつつありますよ
我が家は、HDDレコーダを捨て、テレビサーバーに進化することにしました。
と、大げさなこと書いてますが、要するにTS抜きサーバー環境を構築しようって話しです。
HDDレコーダーも7年ぐらい経ったので、買い替えの時期だなーと思いつつ、市場を見ると、代わり映えのない機器ばかりの割には高いなと
TVは、TVerで良いのじゃないかと思うのですが、家族でめっちゃ使う人が、必須アイテムらしいので解決することにしました。
システム構成としては、電気代のかから無さそうなPCに、TS抜きチューナーを複数付けて、MirakurunとEPGStationで運用しようかと
出先からも視聴出来るように、nginxで公開し、Google認証機能も付けます。
録画フォルダをDLNAで公開したり、sambaでWindows共有も有りです。
FireStickにVLCとかをインストールして見たりも有りです。
ということで、行ってみよう
必要なハードウェア
PC
FUJITSU ESPRIMO Q556/R Core i5 のやつ メモリ 8GBぐらい 小さくってちゃんと4コアでお手頃です <- 当然、ヤフオクでゲットする
こいつは、nvmeなSSDとSATAなSSDを同時に載せれますよ。録画データの保存とOS領域を分けておきたいよね
キーボードを接続しないと起動時にうるさいので、BIOSでkeyboard error を無効にしましょうね
最初、RaspberryPI4で構築したんですが、エンコードパワーが足りないので、Intelアーキテクチャに頼りました
TS抜きチューナと変換コネクタ
MyGica T230C x 必要なだけ
このUSBドングル型のTS抜きチューナーは、AliExpressの公式ショップでのみ販売しているようで、入荷しては売り切れてますね。
在庫があったら、即購入しましょう。
PX-Q1UD を使ってみたのですが、ドロップ酷くって使えませんでした。良い凡ドライバを見つけれなかったか、Ubuntuとの相性か?
ICカードリーダ
B-CASカード
どうにかして手に入れる
必要なスキル
Ubuntuのセットアップ
Dockerの簡単な使い方
Linuxでのテキスト編集
パーミッションの変更の仕方
nginxを構築出来る知識
httpsなサイトを構築出来る知識
1.Ubuntuインストール
とにかく、サーバーを構築しないと話が進みませんよね
こんな記事よんでる人なら、わかるでしょなことは、書きませんよ。厳し目に行きます。
とっとと、PCにUbuntu 24.04をインストールして下さい。
出来ればLVMで論理ボリュームを作成しておきましょうね。<- 録画領域を後で増やしたい人は、LVMが良いですね
SSHとか、日本語とかtimezoneを良い感じに設定しましょう。
Dockerが必須なので、ここを参考にして、インストールしてね。 docker composeも必須です。
わからない人は、chatgptに聞いて下さい。
※蟹さんドライバ(r8169)が違うらしいので修正する場合、以下で切り替えることが出来ます。必須ではないです。
apt install r8168-dkms
確認
ethtool -i enp1s0
作業は、rootでやらないとダメなので、
sudo -s
です。
2.T230c用ドライバ インストール
これは、簡単で、armでもx64でも同じ物を使用出来ます。
git clone https://github.com/osmc/dvb-firmware-osmc.git
cp dvb-firmware-osmc/{dvb-demod-si2168-d60-01.fw,dvb-tuner-si2141-a10-01.fw} /lib/firmware/
3.ICカードリーダの確認
ICカードリーダを用意していますが、B-CASが認識出来ているかチェックします。
ダメなら、もっとまともな ICカードリーダを購入しましょう。
apt install -y pcscd libpcsclite-dev libccid pcsc-tools
pcsc_scan
> Japanese Chijou Digital B-CAS Card (pay TV) と出ればOK
4.チャンネルを作っていきまーす
ここは、結構、長旅になります。
まず、スクリプトを作成します。
mkchconf.sh
#!/bin/sh
for ch in `seq 1 3`; do
fr=`expr \( $ch - 1 \) \* 6 + 93`
echo "[${ch}]"
echo "\\tFREQUENCY = ${fr}000000"
echo "\\tSYMBOL_RATE = 5274000"
echo "\\tDELIVERY_SYSTEM = DVBC/ANNEX_A"
echo ""
done
for ch in `seq 4 12`; do
if [ $ch -lt 8 ]; then
fr=`expr \( $ch - 4 \) \* 6 + 173`
else
fr=`expr \( $ch - 8 \) \* 6 + 195`
fi
echo "[${ch}]"
echo "\\tFREQUENCY = ${fr}000000"
echo "\\tSYMBOL_RATE = 5274000"
echo "\\tDELIVERY_SYSTEM = DVBC/ANNEX_A"
echo ""
done
for ch in `seq 13 62`; do
fr=`expr \( $ch - 13 \) \* 6 + 473`
echo "[${ch}]"
echo "\\tFREQUENCY = ${fr}000000"
echo "\\tSYMBOL_RATE = 5274000"
echo "\\tDELIVERY_SYSTEM = DVBC/ANNEX_A"
echo ""
done
for ch in `seq 13 22`; do
if [ $ch -lt 22 ]; then
fr=`expr \( $ch - 13 \) \* 6 + 111`
else
fr=`expr \( $ch - 22 \) \* 6 + 167`
fi
echo "[C${ch}]"
echo "\\tFREQUENCY = ${fr}000000"
echo "\\tSYMBOL_RATE = 5274000"
echo "\\tDELIVERY_SYSTEM = DVBC/ANNEX_A"
echo ""
done
for ch in `seq 23 63`; do
if [ -n "$1" -a $ch -gt 23 -a $ch -lt 28 ]; then
fr=`expr \( $ch - 24 \) \* 6 + 233`
else
fr=`expr \( $ch - 23 \) \* 6 + 225`
fi
echo "[C${ch}]"
echo "\\tFREQUENCY = ${fr}000000"
echo "\\tSYMBOL_RATE = 5274000"
echo "\\tDELIVERY_SYSTEM = DVBC/ANNEX_A"
echo ""
done
catvrec.sh
#!/bin/sh
DEVNO=$1
for ch in `seq 1 62`; do
dvbv5-zap -C JP -a ${DEVNO} -c channels.conf -r -P ${ch} -t 4 -o ${ch}.ts
done
for ch in `seq 13 63`; do
dvbv5-zap -C JP -a ${DEVNO} -c channels.conf -r -P C${ch} -t 4 -o C${ch}.ts
done
chlist.sh
#!/bin/sh
for ch in `seq 1 62`; do
if [ -f ${ch}.ts ]; then
./tschput ${ch}.ts | nkf --ic=CP932 | sed -e "s/^ */${ch}\t/;s/ */\t/g"
fi
done
for ch in `seq 13 63`; do
if [ -f C${ch}.ts ]; then
./tschput C${ch}.ts | nkf --ic=CP932 | sed -e "s/^ */C${ch}\t/;s/ */\t/g"
fi
done
mkchyml.sh
dvb-toolsインストール
apt-get install -y dvb-tools
ザッピングしてチューナーからチャンネルを取得
channels.confの作成
./mkchconf.sh > channels.conf
dvb_channel.confの作成
チャンネルスキャン -> dvb_channel.conf が作成される
dvbv5-scan -C JP -a 0 -N channels.conf
チャネル情報取得 4秒 受信した x.TS 達が出来る
./catvrec.sh 0
さらに、TS 達から 日本語(SJIS)へ抽出する
apt install nkf
wget http://www.areanine.gr.jp/~nyano/archives/nikki/tschput.c
gcc tschput.c -o tschput
./chlist.sh > channels.txt
最後にMirakurun用のchannels.yml を作成する。
./mkchyml.sh GR < channels.txt > channels.yml
この channels.yml は、全て GR として記録されているし、スクランブルされていて見れないチャンネルも含まれているので、適宜編集して自分に合う物にしておこう。
例えば、見れないチャンネルは、削除し、BSの場合、GRのとこをBSに変更等です
5.tunner.ymlの作成
TS抜きチューナーの登録用ファイルです。
- name: T230_1
types:
- BS
- GR
command: dvbv5-zap -C JP -a 0 -c /app-config/channels.conf -r -P <channel>
dvbDevicePath: /dev/dvb/adapter0/dvr0
decoder: arib-b25-stream-test
- name: T230_2
types:
- BS
- GR
command: dvbv5-zap -C JP -a 1 -c /app-config/channels.conf -r -P <channel>
dvbDevicePath: /dev/dvb/adapter1/dvr0
decoder: arib-b25-stream-test
この例では、2つのチューナーを接続する場合です。
1つの場合、2つ目は、削除し、3つ以上だと、T230_3 等というように増やしましょう。
6.mirakurun と epgstation のセットアップ
まず、docker compose を使用します。
Ubuntuにセットアップしておいて下さい。
セットアップだ
cd ~
git clone https://github.com/l3tnun/docker-mirakurun-epgstation.git
cd docker-mirakurun-epgstation
cp docker-compose-sample.yml docker-compose.yml
cp epgstation/config/enc.js.template epgstation/config/enc.js
cp epgstation/config/config.yml.template epgstation/config/config.yml
cp epgstation/config/operatorLogConfig.sample.yml epgstation/config/operatorLogConfig.yml
cp epgstation/config/epgUpdaterLogConfig.sample.yml epgstation/config/epgUpdaterLogConfig.yml
cp epgstation/config/serviceLogConfig.sample.yml epgstation/config/serviceLogConfig.yml
docker compose run --rm -e SETUP=true mirakurun
設定をコピーだ
cp channels.conf ~/docker-mirakurun-epgstation/mirakurun/conf/.
cp tuners.yml ~/docker-mirakurun-epgstation/mirakurun/conf/.
cp channels.yml ~/docker-mirakurun-epgstation/mirakurun/conf/channels.yml
7.実行だ
起動方法
cd ~/docker-mirakurun-epgstation
docker compose up -d
停止方法
cd ~/docker-mirakurun-epgstation
docker compose down
8.アクセスだ
http://サーバーIP:8888/
見れたら、おめでとうだ
番組表は、数分間待つと出てくるはず
番組表が更新されれば、放送中も見れるようになります。
そうそう、動画の格納場所ですが、docker-compose.yml に指定されているので、これを修正します。
version: '3.7'
services:
epgstation:
volumes:
- /video:/app/recorded
9.nginxでリバースプロキシして、google認証で守られた epgstation を外から見れるようにしよう
まず、google認証するのは、oauth2-proxy でやります。
こいつは、nginxにgoogle認証機能を付加する代理認証proxyです。
動作させるのは簡単で、oauth2_proxy.cfg を作成して、このファイルを引数に起動すれば良いだけです。
google認証を行うには、認証用のOAuth2.0 キーが必要です。
なので、google cloud の APIとサービス - 認証情報 - OAuth 2.0 クライアント ID(ウェブアプリケーション用) とシークレットを取得して下さい。
承認済みの JavaScript 生成元:https://[外用ドメイン]
承認済みのリダイレクト URI:https://[外用ドメイン]/oauth2/callback
外用ドメインは、ドメイン屋さんで買って下さい。
google認証サンプル
/etc/oauth2_proxy/oauth2_proxy.cfg
http_address = "127.0.0.1:4180"
redirect_url = "https://[外用ドメイン]/oauth2/callback"
upstreams = ["http://localhost:4180/"]
client_id = "hogehoge.apps.googleusercontent.com"
client_secret = "hogehogesecret"
oidc_issuer_url = "https://[外用ドメイン]"
provider = "google"
cookie_secret = "hogehogerandom"
authenticated_emails_file = "/etc/oauth2_proxy/epgemail.txt"
cookie_secretは、コマンドで出力しても良いですし、どこぞのサイトで24バイトで出力させた物を使えば良いです。
head -c 16 /dev/urandom | base64
自分のサーバーで、TV視聴するのに、誰でもかれでも観れるのは良くないですよね。
なので、以下のファイルを作って、必要なアカウントを絞り込みましょう
認証ファイルのサンプル
/etc/oauth2_proxy/epgemail.txt
起動方法
nohup oauth2-proxy --config /etc/oauth2_proxy/oauth2_proxy.cfg &
こいつを Docker化しておくのがお勧めです。
Dockerfile
docker-compose.yml
これを nginx で定義すると、以下です。
SSLは、Let's encryptを使ってます。
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name [外用ドメイン];
index index.html index.htm;
location / {
auth_request /oauth2/auth;
error_page 401 = /oauth2/sign_in;
proxy_pass http://[内部epgstationアドレス]:8888;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /oauth2/ {
proxy_pass http://127.0.0.1:4180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
}
location = /oauth2/auth {
proxy_pass http://127.0.0.1:4180;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_set_header Content-Length "";
proxy_pass_request_body off;
}
location /api/config {
proxy_pass http://[内部epgstationアドレス]:8888;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
}
ssl_certificate /etc/letsencrypt/live/[外用ドメイン]/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/[外用ドメイン]/privkey.pem;
# managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
後は、ルーターで、TCP:443を、作ったサーバーに向ければ完成です
10.ハードウェアエンコーディングしてみたい
色々と しっかり動作するようになると欲をかきますよね
じゃー、エンコードをハードウェアでやってみたいですよねっねっ 早いし CPU食わないし
ということで、CPUの底力を使ってハードエンコへ誘いましょう
手順としては、ホストで、ハードエンコ用のデバイスファイルを作成し、それをコンテナへ公開します。
コンテナ内で、ハードエンコ用の設定定義を行います。
ffmpegを使うコンテナを再構成し、再起動すれば完成です。
※修正ポイントを色替えしてます。
まず、ホスト側での準備です。
apt install vainfo
apt-get -y install i965-va-driver
echo 'KERNEL=="render*" GROUP="render", MODE="0666"' | sudo tee /etc/udev/rules.d/99-render.rules
udevadm control --reload-rules && sudo udevadm trigger
これで、準備Ok
vainfoで、使えるハードエンコを見ておきましょうね。
次にDocker側です
docker-mirakurun-epgstation/docker-compose.yml の追記修正です
version: '3.7'
services:
epgstation:
devices:
- /dev/dri/renderD128:/dev/dri/renderD128
docker-mirakurun-epgstation/epgstation/debian.Dockerfile の追記修正です
apt-get -y install yasm libx264-dev libmp3lame-dev libopus-dev libvpx-dev && \
apt-get -y install libx265-dev libnuma-dev i965-va-driver && \
#ffmpeg build
mkdir /tmp/ffmpeg_sources && \
cd /tmp/ffmpeg_sources && \
curl -fsSL http://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.bz2 | tar -xj --strip-components=1 && \
./configure \
--prefix=/usr/local \
--disable-shared \
--pkg-config-flags=--static \
--enable-gpl \
--enable-libass \
--enable-vaapi \
--enable-libfreetype \
--enable-libmp3lame \
--enable-libopus \
--enable-libtheora \
--enable-libvorbis \
--enable-libvpx \
--enable-libx264 \
--enable-libx265 \
--enable-version3 \
--enable-libaribb24 \
--enable-nonfree \
--disable-debug \
--disable-doc \
docker-mirakurun-epgstation/epgstation/config/enchw.js の作成です
まず、エンコードスクリプトをコピーして、それを修正します。
copy enc.js enchw.js
enchw.js
~~~~~
// 字幕用
Array.prototype.push.apply(args, ['-fix_sub_duration']);
// input,ビデオストリーム設定
Array.prototype.push.apply(args, ['-hwaccel', 'vaapi', '-vaapi_device', '/dev/dri/renderD128']);
Array.prototype.push.apply(args, ['-i', input]);
Array.prototype.push.apply(args, ['-map', '0:v', '-c:v', 'h264_vaapi']);
Array.prototype.push.apply(args, ['-vf', 'format=nv12,hwupload']);
// オーディオストリーム設定
if (isDualMono) {
Array.prototype.push.apply(args, [
'-filter_complex',
'channelsplit[FL][FR]',
'-map', '[FL]',
'-map', '[FR]',
'-metadata:s:a:0', 'language=jpn',
'-metadata:s:a:1', 'language=eng',
'-ac', '1',
]);
} else {
Array.prototype.push.apply(args, ['-map', '0:a']);
}
Array.prototype.push.apply(args, ['-c:a', 'aac']);
// 字幕ストリーム設定
Array.prototype.push.apply(args, ['-map', '0:s?', '-c:s', 'mov_text']);
// 品質設定
Array.prototype.push.apply(args, ['-profile:v', '77', '-level', '40', '-qp', '26']);
// 出力ファイル
Array.prototype.push.apply(args, [output]);
~~~~~
(async () => {
~~~~~
child.on('close', (code) => {
if( code == 251 ) {
//仕方無いか、誰か解決して
process.exitCode = 0;
} else {
process.exitCode = code;
}
~~~~~
});
})();
docker-mirakurun-epgstation/epgstation/config.yml の追記修正です
~~
encode:
- name: H.264Hard
cmd: '%NODE% %ROOT%/config/enchw.js'
suffix: .mp4
rate: 4.0
~~
これで、docker-mirakurun-epgstation-epgstation のイメージを破棄して、再起動すればOkのはずです。
docker compose down
docker image rm docker-mirakurun-epgstation-epgstation:latest
docker compose up -d
エンコードメニューで、H.264Hard が選択出来ればOkです。
enchw.jsは、コピーして色々とバリエーションを作ることで、さまざまなエンコを楽しめますよ
ついでに、放映中のとこも、ハードエンコにしてしまいましょう。
※チューニング所を赤くしておきました。
小ネタ
動画ファイル移動
そういったインターフェースが無いので、データベースを修正して移動します。
動画の格納場所を調査します。
docker exec -it docker-mirakurun-epgstation-mysql-1 mysql -u epgstation -pepgstation epgstation -e "select id, filepath from video_file;"
+-----+------------------------------------------------------------------------------------------------------------------+
| id | filepath |
+-----+-------------------------------------------------------------------------------------------------------------------+
| 2 | 2024年06月13日08時00分00秒-hogehoge[解][字].mp4 |
| 6 | 2024年06月14日08時00分00秒-hogehoge2[解][字].mp4 |
対象動画のidを指定して、ディレクトリ等(hogedir/)を付け加えます。
docker exec -it docker-mirakurun-epgstation-mysql-1 mysql -u epgstation -pepgstation epgstation -e "update video_file set filepath = concat('hogedir/' ,filepath) where id = 6;"
この後、実際の動画ファイルを移動しましょう。
一括動画削除とリスト
APIを使って動画をリストアップしたり、一括削除します。
python3でスクリプト化して、日々使いましょう。
第1引数:キーワード
オプション引数:-delete 削除
オプション引数:--yes 削除の時、問答無用
listrecorded.py
番組リスト表示と予約
番組表を検索し、ルールに追加します。
番組改編の時とかに、新ドラマを一気に予約する時とかに使います
使い方)
検索日時範囲:7
ジャンル:3
キーワード:[新]
予約
./gettv.py -dayrange 7 -genre 3 -keyword '[新]' -reserve