#show tech >>log

Raspberry Pi 3B で自宅のテレビをどこでも見る ── 構想編

# Raspberry Pi 3B で自宅のテレビをどこでも見る ── 構想編

>> はじめに - 転がっていた Pi 3B

引き出しに Raspberry Pi 3B が転がっていた.
2016年ごろの機体でメモリは 1GB.買った当時は何かに使うつもりだったはずだが,結局そのままになっていたやつだ.

これで地デジを受信して,手元のスマホから見られるようにしたら面白いのでは?と思いついてしまった.外出先からでも自宅のテレビが見られる,というやつだ.調べてみると先人がいくらでもいる.

ただ結論から言うと,この 1GB という数字が,その後の選択のほとんどを決めた.部品を選ぶたびに「それは載るのか」を問われ続けることになる.構想編ではその取捨選択を書いておく.

>> 1GB という制約

>>> Mirakurun ではなく mirakc

チューナーを管理する部分は,日本の地デジだと Mirakurun が定番.情報も一番多い.ただ Node.js 実装で,常駐がそれなりに重い.

代わりに選んだのが mirakc だ.Rust で書かれた実装で,常駐が 50MB 程度に収まる.公式のコンテナイメージに recdvb recpt1 arib-b25-stream-test mirakc-arib が最初から同梱されているのもありがたい.このあたりを自前でビルドし始めると,それだけで一晩溶ける.

>>> KonomiTV は Pi では動かせなさそう

視聴環境まで含めた全部入りとして KonomiTV がある.画面も綺麗で,これが動くなら自分で UI を書く必要もない.かなり惹かれた.

が,作者が Readme で 「ラズパイ4/5はサポート予定なし」 と明言している.対応しているエンコーダが QSVEncC / NVEncC / VCEEncC / rkmppenc の4つで,Pi の h264_v4l2m2m が入っていない.つまり Pi ではソフトウェアの x264 になり,実時間の変換に届かない.ちなみに Pi 5 はハードウェアエンコーダ自体が載っていないので,そもそも土俵に上がれない.

やるなら Intel N100 か RK3588 あたりの板を買え,という話だ.まぁそれはそうなんだが,今回は転がっていた 3B でやるのが趣旨なので見送ることに.

面白いのは,KonomiTV は mirakc をバックエンドにできること.既定の接続先が Mirakurun の URL になっているだけで,mirakc は互換の API を持っている.将来べつの機械を建てたとしても,チューナーは Pi 3B に挿したままでよいわけだ.そう考えると mirakc を選んでおくのは後々効いてくる.

>>> 番組表(EPGStation)は諦める

番組表と録画がほしいなら EPGStation を被せるのが定番だ.ただこれも Node で,200〜250MB は持っていかれる.

ここは見送ることにした.理由は容量そのものよりも切り分けの話で,最大のリスク(CPU が実時間に追いつくか)の上に第二のリスクを重ねると,転けたときにどちらが原因か分からなくなる.半日は溶ける.

外しておけば ffmpeg に回せるメモリが 400MB 超まで増える.しかも mirakc は残すので,後から被せられる.捨てる作業が発生しないなら,先に載せる理由はない.

>>> Docker ではなく Podman

コンテナで動かすのは決めていたが,dockerd + containerd は常駐だけで 100〜150MB を食う.1GB の機体では払いたくない出費だ.

Podman はデーモンレスで,常駐が 10MB 程度.そして同じ OCI イメージがそのまま動く.mirakc の公式イメージも何も変えずに使える.ここは迷わなかった.

>> JSMpeg という寄り道

映像をブラウザへ届ける方式で,途中 JSMpeg に寄り道した.Canvas に直接描画するので遅延が小さい,という触れ込みのやつだ.HLS だと6〜10秒は遅れるので,そこが縮むなら悪くない.

結論は却下.理由を図にするとこうなる.

                エンコード側(Pi 3B)             伝送          デコード側(スマホ)
─────────────────────────────────────────────────────────────────────────
本構成          MPEG-2復号(SW)H.264(HW)     HLS/HTTP      H.264(HW=専用回路)
HLS/H.264       ~~~~~~~~~~~~~    ^^^^^^^^^                   ^^^^^^^^^^^^^^^^^
                CPUはここだけ     ほぼ無料                     電池を食わん

JSMpeg          MPEG-2復号(SW)MPEG-1(SW)    WebSocket     MPEG-1(JS=CPU)
                ~~~~~~~~~~~~~    ~~~~~~~~~~                  ~~~~~~~~~~~~~
                CPU              ★ここもCPU                   ★ここもCPU
                                 HWエンコーダが遊ぶ            発熱・電池

MPEG-1 にはハードウェアエンコーダが無い.Pi 3B の bcm2835-codec は H.264 専用なので,JSMpeg に食わせる MPEG-1 を作るには CPU で符号化することになる.せっかくの専用回路が丸ごと遊ぶ.

しかも MPEG-1 は同じ画質を出すのに H.264 の2〜3倍のレートを要る.「外では通信量を軽くしたい」という目的と真逆だ.

もうひとつ,<canvas> にすると <video> が持っている機能を全部失う.PiP,AirPlay,ロック画面からの再生操作,バックグラウンド再生,進捗バー,全画面.どれも後から自分で書けるものではない.

JSMpeg が輝くのは「320x240 の監視カメラ,ローカル網,遅延が業務要件」という場面だと思う.電池で動く端末でフルセグを長時間見る用途とは真逆,というのが結論だった.

遅延が気になったときの手札は JSMpeg ではなく,セグメント長を詰めるか,go2rtc + WebRTC を足すかの2枚にしておく.後者なら H.264 のまま流せるので,Pi 3B のエンコーダもスマホのデコーダも生きたままだ.

>> 公開せず,tailnet の中だけに閉じる

最初は Tailscale の Funnel で外に公開するつもりでいた.そのほうがどの端末からでも見られる.

ただ Funnel は認証の仕組みを持たない公開経路で,守りは自分で仕込む秘密の cookie だけになる.テレビが誰でも見られる状態というのはさすがにまずい.

そこで tailscale serve に切り替えて,tailnet の中からしか到達できない形にした.こうすると守りは Tailscale の認証そのもの,つまりデバイス登録と ACL になる.自分で書いた cookie ゲートより遥かに堅い.

結果として cookie ゲートも,公開時間を絞るタイマーも,VPS を経由する案も全部要らなくなった.nginx の設定も 52行から 33行に縮んだ.機能を足すのではなく,前提を1つ変えたら周りが勝手に減った形だ.こういうのは気持ちがいい.

視聴先は https://tvpi.xxxxx.ts.net/ のような形になる.tailnet の中にいる端末からしか開けない.

>> メモリ収支を先に引いてみる

部品が決まったところで,載るかどうかを先に計算しておいた.

1024 MB
 − gpu_mem 128 MB          → Linux が見るのは 約 896 MBOS Lite 常駐 約 100 MB   → 使えるのは       約 780 MB
────────────────────────────────────────────────
   podman + conmon               約  10 MB
   mirakc                        約  50 MB
   ffmpeg (視聴中のみ)200 MB
   nginx + 切替API30 MB
────────────────────────────────────────────────
   残り                          約 400 MB 超    ← 余裕がある

400MB 残るなら十分だ.ここに EPGStation を載せると 150〜200MB まで落ちるので,やはり最初は外しておいて正解だった.

デスクトップは入れない.OS は Raspberry Pi OS Lite にする.Ubuntu ではなく Raspberry Pi OS を選んだのは,h264_v4l2m2m が Pi 財団のカーネルの機能だからだ.これが本構成の心臓部なので,ここを外すわけにいかない.vcgencmd で電圧や温度を見られるのも,あとで効いてくることになる.

>> まとめ

構想編でやったのは,要するに引き算だった.

部品 選んだもの 落としたもの
チューナー管理 mirakc Mirakurun(重い)
視聴環境 自作ページ KonomiTV(Pi 非対応)
番組表 載せない EPGStation(後から被せられる)
コンテナ Podman Docker(常駐が重い)
伝送 HLS + H.264 JSMpeg(HWエンコーダが遊ぶ)
公開範囲 tailnet 内のみ Funnel 公開(認証が無い)

1GB という制約は厳しいが,選択肢が減るぶん迷わないという副作用もあった.載らないものは最初から候補に入らない.

次は 構築編・前編.実際に組んでみたら,想定していなかったところで半日溶かすことになる.電源とコーデックの話だ.

📄Arrow icon of a page linkRaspberry Pi 3B で自宅のテレビをどこでも見る ── 構想編

📄Arrow icon of a page linkRaspberry Pi 3B で自宅のテレビをどこでも見る ── 構築編・前編

📄Arrow icon of a page linkRaspberry Pi 3B で自宅のテレビをどこでも見る ── 構築編・後編