タイムシフト録画(全録)
タイムシフト録画は,mirakc
0.17.0
以降で利用可能です.
Mirakurunには無い機能として,mirakcはタイムシフト録画(いわゆる全録)を実装しています.機能の細かい説明は後回しにして,動かしてみましょう.
まず,タイムシフト録画用のフォルダーとファイルを作成します.
$ mkdir timeshift
$ fallocate -l 1638400000 timeshift/nhk.timeshift.m2ts
$ fallocate -l 1638400000 timeshift/bs1.timeshift.m2ts
$ ls -lh timeshift
total 3.1G
-rw-r--r-- 1 pi pi 1.6G Mar 18 07:21 bs1.timeshift.m2ts
-rw-r--r-- 1 pi pi 1.6G Mar 18 07:19 nhk.timeshift.m2ts
ディスク容量が足りない場合,ファイル作成に失敗します.十分な空き容量を作ってから再チャレンジしてください.
フォルダーとファイルの作成に成功したら,docker-compose.yml
を修正し,これをmirakc
コンテナーにマウントします.
# 追加部分のみ抜粋
services:
mirakc:
volumes:
- ./timeshift:/var/lib/mirakc/timeshift
NHK総合とBS1をタイムシフト録画するようにconfig.yml
を修正してみます.
# 追加部分のみ抜粋
timeshift:
recorders:
nhk:
service-triple: [32736, 32736, 1024]
ts-file: /var/lib/mirakc/timeshift/nhk.timeshift.m2ts
data-file: /var/lib/mirakc/timeshift/nhk.timeshift.json
num-chunks: 10
bs1:
service-triple: [4, 16625, 101]
ts-file: /var/lib/mirakc/timeshift/bs1.timeshift.m2ts
data-file: /var/lib/mirakc/timeshift/bs1.timeshift.json
num-chunks: 10
準備は整いました.mirakcを起動してください.
$ sudo docker compose up -d
タイムシフト録画が動いていれば,以下のように表示されます.
$ curl -sG http://localhost:40772/api/timeshift | jq .[].name
"nhk"
"bs1"
起動直後は何も録画されていないので何も視聴できませんが,1,2分程度待つと視聴可能な状態になります.
# 直後は0で視聴できないが,そのうち0以外が表示されるようになる
$ curl -sG http://localhost:40772/api/timeshift/bs1 | jq .duration
75420
ffplay
がインストールされているデスクトップ環境上で以下のコマンドを実行すると,最初の番組からタイムシフト再生されます.
# raspberrypi上ではなく,別のデスクトップ環境上で実行すること
curl -sG http://raspberrypi.local:40772/api/timeshift/bs1/stream | ffplay -
上記のWeb APIはタイムシフト録画をライブ視聴相当でストリーミングします.そのため,シークはできませんが,視聴中の番組が終了したら次の番組が自動で再生されます.
特定の番組のみを視聴したい場合は,以下のWeb APIを使います.
ID=$(curl -sG http://raspberrypi.local:40772/api/timeshift/bs1/records | jq .[0].id)
curl -sG http://raspberrypi.local:40772/api/timeshift/bs1/records/$ID/stream | ffplay -
こちらはWeb API呼び出し時に録画されているところまでが再生可能範囲になります.シーク可能ですが,録画中の番組を再生した場合,途中までしか再生されません.普通は録画完了した番組の再生に使います.
タイムシフト録画とは?
冒頭でも書きましたが,mirakcのタイムシフト録画は,いわるゆ全録機能です.以下のような特徴を持ちます.
- 固定サイズのファイルをリングバッファーとして,指定サービスのTSストリームを録画します
- サイズは
config.yml
で指定します
- サイズは
- サイズ上限に達すると,古い録画から順番に消えていきます
- ファイルをある固定サイズのチャンクに分割し,この単位で消していきます
- mirakcを停止しても録画は消えません
- 再起動しても前の録画を残し,続きから録画を再開します
固定サイズのファイルを使って録画を行うため,タイムシフト録画を行ない続けても,ディスクを際限なく消費してしまうことはありません.
タイムシフト録画が設定されると,mirakcは指定されたサービスの番組をひたすら録画し続けます.このような性質の機能であることから,タイムシフト録画を有効にしたmirakcを起動する場合は,以下の条件を満たしておく必要があります.
- タイムシフト録画の数以上のチューナーを用意する
- mirakcを起動することは可能ですが,タイムシフト録画数はチューナー数を超えません
- 十分なディスク容量を用意する
- 容量が足りないと書き込みエラーが発生して機能しないため,予め
fallocate
などでts-file
を最大サイズで確保しておくことが望ましいです ts-file
の最大ファイルサイズは,チャンクサイズ(既定値は163840000
で約160MB)にnum-chunks
を掛けた数data-file
の最大ファイルサイズは計算不可能ですが,多くても数MB程度
- 容量が足りないと書き込みエラーが発生して機能しないため,予め
- 常時起動
- NASに書き込むのはお勧めしません(NASのファームアップデート時に停止する必要があるため)
このような条件を満たす必要があるため,タイムシフト録画用のmirakcは専用の独立サーバーとして運用することをお勧めします.その上で,タイムシフト録画の対象となるチャンネルのみをconfig.yml
に定義します.こうしておけば,EPG関連データの取得に失敗することはなくなります.なぜなら,常時チューナーが開いているためです.一方,タイムシフト録画の対象になっていないチャンネルをconfig.yml
に定義していると,そのチャンネルのEPG関連データの取得のためチューナーを開こうとするため,チューナーの数がタイムシフト録画の数以上存在しないとエラーが発生します.
タイムシフト録画に必要なチャンク数の計算方法
先に説明したように,タイムシフト録画用のts-file
は,チャンクサイズ(chunk-size
)とチャンク数(
num-chunks
)で決まります.
ts-file-max-size = chunk-size * num-chunks
タイムシフト録画に使用するディスクサイズが既に決まっている場合には,それを超えないようにチャンク数を決めることになります.例えば,既定値のチャンクサイズで1チャンネルを最大1TBだけタイムシフト録画したい場合は,
num-chunks = ts-file-max-size / chunk-size = 1000000000000 / 163840000 = 6103
となります.
録画期間からチャンク数を計算する場合は,少し面倒な計算が必要です.例えば,BS1を一週間分タイムシフト録画しようと考えた場合,
- BS1のTSストリームのビットレートは約20Mbps
- 一分間の録画に必要なサイズは
20M bits * 60 / 8
で約150MB(既定値の1チャンクで大体1分間録画できる)- タイムシフト録画対象のサービスに依存しますが,既定値の1チャンクは約1〜3分に相当するサイズです
150 * 60 * 24 * 7 = 1512000
で約1.5TB
となります.これらを計算式に当てはめると,
num-chunks = 1512000000000 / 163840000 = 9228
となるため,num-chunks
に10000
を指定しておけば,余裕を持って一週間分タイムシフト録画できると期待できます.この場合のts-file
の最大ファイルサイズは,1638400000000
(約1.6TB)です.
TSストリームのビットレートはサービスごとに異なるため,タイムシフト録画の期間を決めてからチャンク数を求めたい場合には,サービスごとにビットレートを計測する必要があります.また,ビットレートは固定ではなく時間変動するため,上記計算は目安程度と考えてください.
以下は実績値です.参考にしてください.
サービス | chunk-size | num-chunks | 録画可能期間 |
---|---|---|---|
NHK総合1・東京 | 163840000(既定値) | 12000 | 二週間程度 |
NHKEテレ1東京 | 163840000(既定値) | 12000 | 二週間程度 |
NHKBS1 | 163840000(既定値) | 15000 | 二週間程度 |
NHKBSプレミアム | 163840000(既定値) | 15000 | 二週間程度 |
上記各タイムシフト録画のdata-file
はどれも2MBを超えません.そのため,上記設定で4チャンネルのタイムシフト録画を10TBのHDDで行うことが可能です.
データ管理方法
mirakcのタイムシフト録画では,録画データ(TSパケット)ファイル(ts-file
)をチャンクという塊で管理します.そのため,番組の録画が進んでもチャンクがいっぱいになるまで録画済みとは扱われません.
ts-file
+-------------------------------------------------
| Chunk#0 | Chunk#1 | Chunk#2 | Chunk#3 | ...
|xxxxxxxxx|xxx______|_________|xxxxxxxxx|x...
+-------------------------------------------------
| | | |
+-番組#100-+ +-番組#10だがもう-+-番組#10(途中から)---
見ることはできない
上記ではChunk#0
はデータで埋まっているため録画済みとして扱われます.一方,Chunk#1
は現在書き込みを行っているチャンクで,データで埋まるまで録画画済みとは扱われません.Chunk#1
には過去の録画データが記録されている場合がありますが,データは上書きされていきます.
Chunk#2
にも録画データが書き込まれているかもしれませんが,このデータは古くなったものとして扱われます.その結果,古い番組のデータが消えていきます.
TSパケットの他に,録画済み番組情報などを記録しておく必要があり,data-file
はそのために使用されます.data-file
を定期的に更新する必要がありますが,これがチャンク単位で行われるようになっています.
data-file
を削除すると,ts-file
があっても,どこにどの番組が録画されているのかわからなくなり,録画された番組はないものとして扱われます.
タイムシフト・ファイルシステム
mirakcはバックエンド機能しか提供しません.そのため,タイムシフト録画した番組を再生する場合,curl
やjq
などを使って,必要な情報を取得する必要があります.Web UIなどのフロントエンドを実装すればよいのでしょうが,今の所はその計画はありません.
タイムシフト録画した番組を再生できるとはいえ,流石にこのままでは不便なので(作った本人である私も)使いたくはありません.そこで,FUSEを使ってタイムシフト録画した番組を普通のファイルとして扱えるファイルシステムを用意しました.
以下をdocker-compose.yml
に追記してください.
services:
...
mirakc-timeshift-fs:
container_name: mirakc-timeshift-fs
image: mirakc/timeshift-fs
init: true
restart: unless-stopped
cap_add:
- SYS_ADMIN
devices:
- /dev/fuse
volumes:
# タイムシフト録画しているmirakcと同じ設定を使うこと
- ./config.yml:/etc/mirakc/config.yml:ro
# タイムシフト録画ファイルをコンテナーにマップ
- ./timeshift:/var/lib/mirakc/timeshift
# mirakc/timeshift-fsはコンテナー内の/mntにタイムシフト・ファイルシステムをマウントする
# 下記はこれをDockerホストの./timeshift-fsに反映させる
- type: bind
source: ./timeshift-fs
target: /mnt
bind:
propagation: rshared
environment:
TZ: Asia/Tokyo
RUST_LOG: info
timeshift-fs
フォルダーを作成し,追加したコンテナーを起動します.
mkdir timeshift-fs
sudo docker compose up -d mirakc-timeshift-fs
起動に成功すれば,timeshift-fs
にタイムシフト・ファイルシステムがマウントされます.
$ ls timeshift-fs
bs1 nhk
$ ls timeshift-fs/bs1
6052B1C8.BSニュース.m2ts
タイムシフト・ファイルシステムは読み取り専用なので書き込みはできません.録画が進むとファイルが増えたり減ったりします.
普通のファイルとして扱われるので,あとは煮るなり焼くなり好きにできます.試しにSambaでファイル共有してみましょう.
docker-compose.yml
を書き換え
services:
...
samba:
depends_on:
# ./timeshift-fsへのタイムシフト・ファイルシステムのマウント完了後に起動する
- mirakc-timeshift-fs
container_name: samba
image: dperson/samba
command:
# LAN(192.168.0.0/16)からのアクセスのみ許可
- '-g'
- 'hosts allow = 192.168.'
# timeshiftフォルターとして公開(ゲスト・アクセス可)
- '-s'
- 'timeshift;/mnt'
init: true
restart: unless-stopped
ports:
- '139:139'
- '445:445'
volumes:
# タイムシフト・ファイルシステムをコンテナー内にマップ
- ./timeshift-fs:/mnt:ro
environment:
TZ: Asia/Tokyo
samba
コンテナーを起動します.
sudo docker compose up -d samba
エクスプローラーやFinderでSambaに接続し,MPEG2-TSを再生可能なメディアプレーヤーでファイルを開けば,番組が再生されるはずです.
macOSユーザーには,Finderのプレビューを無効にすることをお勧めします.これを有効にしていると,動画のサムネイル画像の生成処理が開始され,Finderが操作不能になる場合があります.また,アプリケーションのメニューからファイルを開くと,Finderのプレビューを無効にしているのに,なぜかサムネイル画像を生成しようとすることがあるようなので,m2tsファイルをメディアプレーヤーに関連付けて,open
コマンドで開くことをお勧めします.
どうもタイムシフト・ファイルシステムのアンマウントがうまくできないようで,それが原因で
mirakc-timeshift-fs
コンテナーの再起動に失敗するようです.そのような場合は,以下のようにアンマウント後にmirakc-timeshift-fs
コンテナーを起動してください.
sudo umount ./timeshift-fs
多重音声(デュアルモノラル)について
タイムシフト録画は,単にTSパケットをファイルに書き込むだけなので,多重音声(デュアルモノラル)な録画を再生する場合,メディアプレーヤーがこれをサポートしていないと2つの音声(例えば,日本語と英語)が同時に再生されます.
多重音声(デュアルモノラル)をサポートしているメディアプレーヤーは数が限られています.例えば,日本向けのTVなどでは音声切り替え可能ですが,Kodiなどはサポートしていません.
非サポートのメディアプレーヤーで正しく再生するためには,再生前にトランスコードする必要があります. フィルター設定で説明しましたが,mirakcのフィルターを使えば,わざわざトランスコード済みのファイルを作成する必要はありません.
以下のsplit-dual-mono
フィルターは,ステレオ音声を2つの音声に分離します.
# ffmpegがインストール済みのカスタムイメージを使うこと
filters:
post-filters:
# See https://trac.ffmpeg.org/wiki/AudioChannelManipulation
split-dual-mono:
command: >-
ffmpeg -i - -hide_banner -vcodec copy
-filter_complex "[0:a]channelsplit=channel_layout=stereo"
-f mpegts pipe:1
音声トラックを切り替え可能なメディアプレーヤーで再生すれば,目的の言語の音声のみを再生できます.
# ステレオ音声が2つのモノラル音声に分離されることを確認
# 実際は多重音声(デュアルモノラル)の録画にフィルターを適用する
STREAM=http://raspberrypi.local:40772/api/timeshift/bs1/stream
curl -sG "$STREAM?post-filters[]=split-dual-mono" | ffprobe
コンソール上のログから,ステレオ音声が分離されていることを確認できます.
Input #0, mpegts, from 'pipe:':
Duration: N/A, start: 1.400000, bitrate: N/A
Program 1
Metadata:
service_name : Service01
service_provider: FFmpeg
Stream #0:0[0x100]: Audio: mp2 ([3][0][0][0] / 0x0003), 48000 Hz, mono, fltp, 384 kb/s
Stream #0:1[0x101]: Audio: mp2 ([3][0][0][0] / 0x0003), 48000 Hz, mono, fltp, 384 kb/s
Stream #0:2[0x102]: Video: mpeg2video (Main) ([2][0][0][0] / 0x0002), yuv420p(tv, bt709, top first), 1440x1080 [SAR 4:3 DAR 16:9], 29.97 fps, 29.97 tbr, 90k tbn, 59.94 tbc
Side data:
cpb: bitrate max/min/avg: 20000000/0/0 buffer size: 9781248 vbv_delay: N/A
欠点として,post-filterでストリームを変換した場合,シークできなくなります.変換によりストリームが動的に生成されるため,HTTPレスポンスはContent-Length
ヘッダーを含まず,HTTPレスポンス・ボディにはチャンク・エンコーディングが適用されるためです.