Adobe Flash の終了と CMAF による HLS/DASH 低遅延配信

投稿日:2018年08月21日

CMAFのメリットは “Common” Media File Format との名前の通り、DASH, HLS, Smooth Streaming 等、いろいろな種類が存在するストリーミングフォーマットの形式を統一する事により、ストレージコストや配信効率等、全般的な利便性を向上させる事にあります。

一方でこれまで低遅延での Live 配信に使われていた Adobe Flash Player は、2020年の終わりにアップデートも配信も終了する事が Adobe より発表されています[1]。

On Demand での動画の配信では、HTTPベースのHLS / MPEG DASH 等が Adobe Flash の代換えの標準技術としてその地位を気付いていますが、Live の動画配信では、現時点では Flash で達成できていた 4~5秒程度の遅延を達成するのは厳しい状況にあります。

このような状況もあり、CMAFの低遅延の部分に関する興味が非常に高いと思われるため、低遅延配信について技術者向けにもう少し掘り下げて見たいと思います。

HLSMPEG DASH等の既存の方式に対するメリット

HLSや DASHの動画ファイルのセグメントサイズを単純に小さくして非常に小さいサイズにする事でも低遅延を実現する事は可能です。

例えば Encoder で作り出す セグメントのサイズを2秒程度にし、バッファーサイズを3セグメント(2秒x3=6秒)にする事でも、おおよそ10秒以下の低遅延で配信する事が可能です。
(Liveの遅延はセグメントのサイズだけでなく、Encoder でのデータの生成遅延やインターネットの旅路の途中での遅延などで、数秒の遅延が加わります)
この時、使用する要素技術は、今でも一般的な30秒~60秒の遅延のLive 配信とまったく同じになります。単純にセグメントが小さくなっただけです。

このように、単純にセグメントサイズを小さくする事でLive 配信は低遅延になって行きます。ただし現実の運用を考えると様々な問題が発生する事になります。
例えば、10秒で配信していたセグメントを1秒セグメントまで縮める例を考えると、簡単に想像しただけでも以下の事が発生します。

・カメラから動画を受け取ったEncoderは、セグメントを作成、送出するために単位時間辺り10倍の IO を処理する必要があるます。
・Live動画をホストする Webサーバー が、Player から受ける HTTP Request は単純に10倍になります。セグメントへのリンクを含むマニフェストファイルの更新頻度も上がるためこちらも頻繁に HTTP Request を投げて更新確認をする必要があります。
・大規模向けのLive配信は、遅れてLive配信に参加して来た人や見逃し配信用にLive配信用にストレージに動画を記録しておきます。こちらのメディアデータのファイルがより細切れになる事でDisk IOも少なくても10倍になる事が想定されます。


↑セグメントを小さくする事で、あちこちの処理能力の高さが求められる

これらの問題はサーバー、ストレージ、ネットワーク機器のパフォーマンスの向上や増強により少しづつ改善していくものではありますが、現実の世界では現在の配信のキャパシティを考慮してセグメントのサイズを決定する必要があります。何よりもインフラに過大な負荷を要求する方法は不安定な配信を招く原因になると考えられます。

このように、セグメントサイズを小さくして低遅延を実現するという方式は、その方向を突き詰める程、力業をインフラに要求する方式になります。実際、この方向性でチャレンジしたものの単純にセグメントを小さくするだけではインフラが耐えられなかった。。安定しなかった。。という話をちらほらと耳にします。

加えて、単純に転送データサイズを小さくする事は、データ転送効率の観点で2つの課題をもたらします。

一つ目は、データ転送時のデータサイズを小さくする事でスループット(単位時間に送信できるデータ量)の低下です。これは送信受信間のやり取りが増える事や、一つのデータに対して必ず通信プロトコルに必要なヘッダーと呼ばれる制御データが付加されて帯域に占める正味のデータ部分の帯域が減って行きます。
例えば 20バイトのデータをTCP で相手に送ろうとすると、20バイトのIPヘッダーと、20バイトのTCPヘッダーを付けるとなると、20バイトを送信するために40Byteのヘッダーデータを付けないといけず、比率として制御データの容量の方が大きくなってしまいます。そのため、小さなデータを送る事は、一般的には転送効率を下げる事に繋がります。

二つ目は動画の圧縮アルゴリズムに由来するものになります。
動画ファイルは分解するとパラパラ漫画の様に連続する一枚一枚の画像で構成されています。

このフレームは、それぞれが完全な画像である必要は無く、ある画像を起点として、その画像から変化のあった部分だけを次の画像に記録する。という方式で効率良くデータをまとめる(=圧縮)事が可能です。
この時、起点となる完全な画像を I-frame(Intra-coded frame)、そこからの変更分を保持する画像を P-frame (Predicted frame)と呼びます。さらに I-frameとP-frameの両方を参照し、さらに情報を節約する事のできる B-frame (By-directoryanilly predicted frame) と呼ばれるものが存在します。

10分の動画があった時、初めの I-Frame 以降を全て P-Frame で構成するという事は一般的には行われません。途中から再生したくなった場合、最初のフレームから再生を開始したい場所までの全てのフレームを使用して動画を生成しなければ再生を開始できなくなり、途中再生のリクエストをする度にこれを行う事は現実的では無いためです。
そのため実際の動画の Encoding では、適当な間隔で I-Frame を挟み込む事で、その地点からの途中再生を可能にするようにEncodingされています。

また、安定した再生を行うには、他のセグメントに頼らず、セグメント単体で再生できる事が望ましいため、通常、セグメントは最低一つの I-Frameを含んでいます。

もし、低遅延を目指しセグメントのサイズを小さくしていくと、最終的にはセグメントに1つの I-Frameしか入ってない状態が究極の小さなセグメントになるはずです。
しかしこれは動画全体で考えると、P-frame も B-Frame も存在せず、圧縮がない巨大なデータを送信しなければならなくなる事を意味する事になります。


↑セグメントを小さくしていくと、究極的には全てが I-Frame という無圧縮の動画ができあがる。

単純にセグメントサイズを小さくして低遅延を目指していく事は、動画の圧縮効率が下がっていく事を意味します。これは配信インフラに対する性能要求を高くする一方で、巨大な動画を送信する事にもなり、配信の不安定さに繋がる要因を大きくする事になります。

また、B -frame は、後続の P-Frame を必要とするため、B-frameを受け取った時点で、ユーザーに画像を提供する事ができません。
そのため超低遅延を目指すためには、再生時の処理に時間的な戻りが必用無い、以下のようなI-frame と P-frame だけで Encdoing された動画が必用になってくると思われます。

CMAFによる低遅延再生の可能性

ここではLive配信の遅延の要素とCMAF chunkによる遅延低減の仕組みについて考えて見ます。

2秒のセグメントを作成する Encoder の例を考えます。上の図では、Encoderで[1][2][3][4]のセグメントの作成が完了しており、[5]のセグメントは作成している最中です。
Player 側で「Now」のタイミングで再生ボタンを押したと想定します。この時、Player側は3つセグメントをバッファーに貯めた後、再生を開始するというコーディングがされているとします。

「Now」の時点で Player側が取得できる最新の3つのセグメントは[2][3][4]になります。一つ2秒のセグメントであるため合計で6秒のバッファーになります。ネットワークの遅延はまったく無く「Now」で Playerの再生ボタンを押した瞬間に[2][3][4]が一瞬で Playerのバッファーに溜まる理想的な環境であるとします。
Playボタンを押した瞬間に再生を開始できるとすると 、Live の状態からの再生遅延は7秒になります(上図の①のケース)。

Player側で3つセグメント(2秒x3)をバッファーとして保持する設定は、ネットワーク環境が悪くなり、次のセグメントが取得できず再生が停止してしまう事できるだけ防ぐための仕組みです。コーディングによるものなので、ネットワーク環境が安定している場合、バッファーを1セグメント(2秒)だけにする事もできます。

Playerのバッファーの設定を1セグメント(2秒)にした場合、「Now」の時点で Player側が取得できる最新のセグメントは[4]になります。
セグメントのダウンロードが一瞬で終わり、同時に再生を開始できるとすると Live の状態からは3秒の遅延で再生が開始される事になります(上図の②のケース)。

 

今度は同じ2秒セグメントであるものの内部に500mses のチャンクを持った CMAFセグメントを考えます。
上の図では、Encoder 側で[4]のセグメントまで書き出した状態で、[5]のセグメントは作成されている最中でEncoder内部では半分までデータができている状況を示しています。
[5]のセグメント全体は完成していないものの、今回はchunkでデータが定義されているので Encoderは、chunk [5a] [5b] を提供可能な状態として保持しています。

「Now」の時点で Player側が取得できる最新の完成したセグメントは[1][2][3][4]になりますが、[5]のセグメントも中身は半分できあがっていてリクエストする事は可能になっています。
Player側のバッファーの設定が1セグメント分(2秒)だとします。
ネットワークの遅延は、全く存在せず「Now」で Playerの再生ボタンを押した瞬間に[5]のセグメントに対するリクエストを行い[5a][5b]が一瞬で Playerのバッファーに溜まります。
動画の再生もセグメントの取得と同時に開始できるとすると、Live の状態から 1秒の遅延で再生が開始される事になります(上図の③のケース)。

ここで、もっとLiveとの遅延を少なくする方法があります。「Play」ボタンを押した瞬間に[5]のセグメントを取得するのでは無く、1.5秒ほど待ちます。
ユーザー視点では動画の再生に待たされる事になりますが、1.5秒待つ事で[6a]のChunkができあがっているはずです。この方法だとLiveからの遅延は 500msecまで短くする事ができます。はじめの動画の再生開始を敢えて遅らせる事で、Liveとの視聴の時間差を短くする事が可能です(この仕組みは CMAFに限った事では無く、通常のDASH / HLSでも同じです)

ここまで書いた話はあくまで机上の話で、実際に極限までバッファーサイズを小さくすると、その分ネットワークの遅延の受けバッファーが空になる(=動画の再生が停止する)確率が高くなります。

 

CMAF低遅延配信に必用なもの

CMAFを使った低遅延配信に必用なものは2つあります。

  • CMAF Chunk を送出できる Encoder
  • Javascript Fetch API を実装した Player

です。

CMAF chunk を出せるEncoder は、把握している限りでは 2018年に入ってから登場しはじめてきています。CMAF という言葉自体は、CMAFに沿った HLS も DASH の両方を表す事ができます。ですので、”chunk”を作れる Encoder である事を確認する必要があります。

Javascript fetch API については後述します。

また、CMAFを使った低遅延配信は、大規模視聴者向けの技術になります。作成された Segment を CDNサーバーにキャッシュして複数視聴者に対して配信する事で、大規模な視聴者にも耐えうる動画配信が可能です。
CMAFの低遅延配信では、上図のように今までもよりもシビアな時間でデータが処理されるのと、CDNを挟むと経由するサーバーも増えます。
そのため実際の配信に向けてはCDN事業者のインフラを通して End to End で配信をしてみた時に、遅延無く chunk のやり取りができるかどうか確認した方が良いでしょう。

小規模視聴者向けの低遅延配信であれば、WebRTC等の技術を使う方が現時点では安全だと思います。

低遅延配信のための周辺技術

Chunked Transfer Encoding

初期のHTTP1.0 ではあるファイルのリクエストをした時に、Conent-Length ヘッダーで送信するファイルのサイズをクライアント側に通知していました。
しかしこの方式では、サーバー側で動的に生成されるようなサイズの決まってないデータはサイズが確定するまでコンテンツをブラウザに送信できなくなってしまいます。
こうした問題を解決するためChunked Transfer Encoding という方式が HTTP1.1 で作成されました。HTTP1.1自体は1999年に公開されている古い技術です。

Encoder 側で例えば 3秒のセグメントを作成しようとした時に、Encoder 自身も実際にセグメントを作成してみないと、そのサイズがどうなるかはわかりません。
ですので Encoder で、セグメントの Encoding が完了しサイズが確定した後、はじめてセグメントが送出できるようになります。

一方で低遅延を目指したい場合、セグメント全体が出来る前に転送を開始する必用があります。Chunked Transfer Encoding は、セグメントのサイズが確定する前に既に存在するデータ分の chunk (固まり) にして転送する事を可能にしています。

尚、Chunked Tranfser Encoding は、HTTP/2 では採用されていません。HTTP/2では Data frame という形でデータが送られるようになっており、これが実質的にデータの”chunk”となっています。そのため HTTP/2 では RFC 7540 [2]では、 chunked transfer encoding は、”MUST NOT be used in HTTP/2″ とされています。

Chunked Transfer Encoding を使用するのかHTTP/2を使用するのかはあくまで手法の話で、サイズの決まってない作りかけのデータを HTTPリクエストで伝搬できる事が目的になります。
HTTP/2はかなり普及してきたとは言え、Live配信 の End to End で使えるのかは微妙な状況では無いかと思っています。

もちろん将来的には End to End で HTTP/2 にはなると思いますが、HTTP/2の(速度的な)効果が見えやすいのは、どちらかというと たくさんのオブジェクトを並行に取得する必用があるWebサイトが多いので、動画の配信において無理に HTTP/2を使う必用もないと思っています。(HTTP/2はHTTP 1.1 に比べて複数の改善があれていますが、Akamai社がHTTP/2の効果デモで公開しているこのような環境が効果が見えやすい良い例だと思います。)

XMLHttpRequest

Webブラウザ上で実行される Player は、Javascript (一部はまだ Flashもありますが) でできていますが、Javascript の Player では、Javascript 内から、HTTP リクエストを行うために、一般的に XMHLHttpRequest (XHR)という関数が使われています。

上記は Chrome の Debug Tool で HLS動画の再生中の ts ファイルのリクエストを示したものです。
「Type」の部分が 「xhr」 となっているのが XMLHttpRequest を表しています。

このXMLHttpRequest 関数は、リクエストしたHTTPのセグメントの全てを受け取った後、関数を抜け、次の処理 (取得したデータの解析など)に移ります。

Chunked Transfer Encoding で、データは少しづつ受け取っていたとしても、XMHLHttpRequest は、セグメント全体 (HTTPレスポンス全体)を受け取るまで関数を抜けません。
ですのでいくらセグメントを少しづつ送ってもらっても Player 側は全てのセグメントのダウンロードを完了後、そのセグメントを再生に回す必用があるのでセグメントサイズが再生遅延に影響してきます。

Fetch関数

一方で、低遅延を目指すためには Player側はセグメント全体(HTTP レスポンス全体) を受け取る前に、受け取ったデータ分だけでも、再生処理をしたいという要求があります。

fetch 関数[3]は、XMLHttpRequest と同様に Javascpript の中で使用できる API です。この API は、HTTPリクエストを行い、HTTPレスポンス全てを受け取る前に、受信中のリクエストデータを非同期で処理する事ができます。現時点で主要なブラウザの最新バージョンでサポートされるようになりました。


↑fetch関数は、現在のモダンブラウザは普通にサポートしはじめた。

fetch API をPlayer に使用すると、HTTP Request が完了する前の受信中のデータを MSE (Media Source Extention) API 等の再生処理を担当する Javascript API にいち早く渡す事ができます。そのため Low Latency に対応した Player は、fetch 関数を使用してデータを処理するようになっています。


↑Wall clock time は、再生側の時間

上記は VisualOn Player の Low Latency デモページ[4]のキャプチャーです。
タイムスタンプ付きのカラーバーの画面を Live動画の代わりとして入力に使い配信しています。”Wall clock time” は再生しているブラウザ側の時間です。
約4秒の遅延で動画が配信されているのがわかります。

この Waterfall chart をブラウザのデバッグ機能で見てみると以下のようになっています。

「Type」の部分が 「fetch」 となっているのが fetch リクエストを表しています。
fetch リクエストを使う事で、ダウンロード中のセグメントをダウンロードが完了する前に受け取った分だけ再生処理にまわしています。

VisualOn Player だけではなく、2018年 4月末にリリースされたMPEG DASH の Reference Player [5] v2.6.8以降からは、Low Latency Mode が追加されて、Low Latency Mode を選択すると XMHLHttpRequest に代わって fetch API を使用するモードが選択できるようになりました。TheOPlayer [6]や Shaka Player [7] 等でも、V2.4.0 (2018/05/24リリース)より fetch を関数を積極的に使用する用になりました。

今後、fetch APIによる再生をサポートした Player が徐々に普及してくると思われます。

CMAF Chunk に対応した Encoder

低遅延配信を実現するためには、CMAF Chunk を送出できる Encoder が必用です。単純に CMAF に対応していると言った場合、同じ Media セグメントファイルで、HLS と DASH の manifest の両方を持っている事を指している場合もあり Chunk を生成している/していないを意識していない場合もあるので、ストレージスペースの効率化に視点を置いた話なのか、低遅延配信を視点においた話なのか、文脈を読む必用があります。

CMAF による低遅延配信を検索すると出てくる BroadThinking 2017年の 以下の デモビデオは、こちらの pdf によると、SIGNALS(OSSであるGPAC のソフトウェア)を利用したEncoder が使われており、よくある市販のハードウェアではなかったようです。GPAC Licensing のページを見ても単純にダウンロードして使用できるエンコーダーがあるようではありませんでした(私が見落としているのかもしれませんが・・)

個人ユースではソフトウェア Encoder を使ったLive 配信は一般的ですが、信頼性がもとめられる業務用の世界では Elemental 等の専用ハードウェアが使われており、Encoder専門ベンダーの CMAF Chunk 対応製品のリリースが待たれる状況でした。

そんな中、2018年の6月頃に Harmonic 社が Hardware Encoder もしくはクラウドサービスという形で、CMAF Chunk に対応した Encoder を投入してきました[8]。

この図では、”Electra XOS” で CMAF Chunk を作成して CDN に HTTP で Ingest (PUSH)する方法と(この場合は、CDN側がオリジンを準備している前提)、クラウド上の “VOS SW Cluster Origin” で CMAF Chunk を作成し、そこをオリジンとしてCDN 側から PULL してもらいエンドユーザーに届ける2通りの方法で対応しているそうです。

また2018年の7月には、ソフトウェアエンコーダーでは無いですが、Wowza のスマホ用アプリ「Go Coder」 (エンコーダー)と、Wowza 、Wowza Player を使って低遅延配信をするための以下のセットップガイドが公開されています。デモビデオではCMAFを使った低遅延配信が行われており、この事から「Go Coder」がCMAF Chunkを作りだし、Wowza Player も Fetchでリクエストを処理するように実装されている事が想像できます(私自身はまだ試していないです)

まとめ

この数年、CMAF Chunk による 低遅延配信がいろいろ賑やかになってきたものの、あくまで実験レベルで、End to End で実現するためのハードルが高い状況でした。
2018年になり Fetch リクエストに対応した Player も多くなり、CMAF Chunk に対応した市販の Encoder も登場し、CDN ベンダーも Chunked Transfer Encoding に対応を明言している会社がでてきました。
一通りの要素技術の取得ハードルは下がってきており、今後、CMAF による 低遅延配信技術をサービスに投入してくる会社も出てくる事が予想されます。

参考リンク

[1] Flash & The Future of Interactive Content  https://theblog.adobe.com/adobe-flash-update/
[2] RFC 7540 https://tools.ietf.org/html/rfc7540
[3] fetch 関数 https://developer.mozilla.org/ja/docs/Web/API/Fetch_API/Using_Fetch
[4] VisualOn Player のデモページ https://www.visualon.com/index.php/html5-player-low-latency-demo/
[5] DASH Rereference Player  https://reference.dashif.org/dash.js/
[6] TheOPlayer のデモページ https://demo.theoplayer.com/test-your-stream-with-statistics
[7]Shaka Player のデモページ https://shaka-player-demo.appspot.com/demo/#asset=https://vm2.dashif.org/livesim/utc_head/testpic_2s/Manifest.mpd;lang=ja-JP;build=uncompiled
[8]Harmonic のブローシュア https://www.harmonicinc.com/media/2018/06/Harmonic_UHD_Solution_Brief.pdf

 

Tags: , ,