初めに
WWDC 2020 で Apple Low Latency HLS が GA してから、はや 2 年。
あまりサポートしているという情報をきかず、Appleのツールでしか確認できてませんでした。
LDASH (CMAF-ULL) はよく聞きますが、LL-HLS の話は全然されてません。
実際にどのようにプレイリストを作るのか分かれば、自分で使えるかも?
というわけで、週末の時間を使って作ってみました。
前提
LHLS とは?
コミュニティベースで生まれた規格で、CMAF-ULL との互換のある規格です。
EXT-X-PREFETCH タグによる、プリロード対象を Chunked transfer で読むという方法で
低遅延を実現しており、Appleを対象としてない、独自の低遅延HLSはコレです。
Apple Low Latency HLS とは?
Apple が提唱している 低遅延HLS の規格となります。
2020 年に beta が取れて、Apple 製のプレイヤーでは受けられるようになっています。
特徴は以下の通りです。
- partial segments: 1セグメントを複数の部分セグメントに分けられます
- Playlist delta updates: 部分セグメント単位でのプレイリスト更新が可能
- Blocking of playlist reload: 当該セグメントが更新されるまで、リクエストをブロック
- Using preload hints: 先読みをサポート
- Rendition reports: マスタープレイリストを参照せず他プレイリストの切り替え
要するに、今までの 1 セグメントを分割可能になり、分割した単位で更新が可能で
プレイリストがアップデートされるまで、リクエストをロングポーリング可能になった
というものになります。
これらをオリジンが実装する必要があり、上記の LHLS のような単純なものではないのが欠点です。
実装
ここでは、ライブ再生に必要な以下の 3 つをサポートしてみます。
- partial segments
- Playlist delta updates
- Blocking of playlist reload
- preload hints
(preload hints は実際に使ってるクライアントを見たことないので、出すだけ出します)
実際に作ってみたのが、以下のリポリトジになります
python 製のツールで、標準入力で受け取ると、HTTPサーバになり
オンメモリで /playlist.m3u8 にプレイリストを出力します。
一応、以前に node.js 製で作ったもの を移植した形です。
node.js でも、Python でもやっていることは同じですので、好きな方をみてください
やっていることは超単純で、TS をデマックスして、キーフレームでセグメント分割します。
評価
実際に LAN 内で通信したところ、delta update と bloking request により
従来の TARGETDURATION より高い頻度で更新が出来ている事が確認できました。
遅延も 1 秒までは Apple のプレイヤーでは抑える事が出来そうです。
1 秒はプレイヤーが強制的にバッファするためになります。
余談
なかなかルールが分からず、mediastreamvalidator のお世話になりました。
Safari でエラー表示してくれればよいのですが...
あとがき
LHLS の方が、オリジン, ストレージ, CDN が chunked-transfer をサポートすれば
楽にスケールするため、あまり乗り気ではないというのが、現状なのかなと思いました。
CMAF-ULL を考えると Apple を無視して LHLS にするのが得策なのかもしれないですね。