HTTPライブストリーミングの概要:AndroidなどのHLS

公開: 2022-03-11

ビデオストリーミングは、現代のインターネット体験の不可欠な部分です。 携帯電話、デスクトップコンピュータ、テレビ、さらにはウェアラブルなど、どこにでもあります。 低速のモバイル接続、WiFi、ファイアウォールの背後など、すべてのデバイスとネットワークタイプで問題なく動作する必要があります。AppleのHTTPライブストリーミング(HLS)は、これらの課題を念頭に置いて作成されました。

最近のほとんどすべてのデバイスには、ビデオを再生するのに十分な速度の最新のハードウェアが搭載されているため、ネットワークの速度と信頼性が最大の問題として浮上しています。 何故ですか? 数年前まで、ビデオを保存および公開する標準的な方法は、RTPのようなUDPベースのプロトコルでした。 これは多くの点で問題があることがわかりました。

  1. コンテンツをストリーミングするには、サーバー(デーモン)サービスが必要です。
  2. ほとんどのファイアウォールは、標準のポートと、http、電子メールなどのネットワークトラフィックタイプのみを許可するように構成されています。
  3. オーディエンスがグローバルな場合は、すべての主要なリージョンで実行されているストリーミングデーモンサービスのコピーが必要です。

もちろん、これらすべての問題は簡単に解決できると思うかもしれません。 ビデオファイル(mp4ファイルなど)をhttpサーバーに保存し、お気に入りのCDNサービスを使用して世界中のどこにでも提供できます。

レガシービデオストリーミングが不足している場所

これは、いくつかの理由で最善の解決策とはほど遠いものであり、効率もその1つです。 オリジナルのビデオファイルをフル解像度で保存すると、接続性の悪い地方や地域のユーザーはそれらを楽しむのに苦労します。 彼らのビデオプレーヤーは、実行時にそれを再生するのに十分なデータをダウンロードするのに苦労します。

したがって、ダウンロードされるビデオの量が再生できる量とほぼ同じになるように、ファイルの特別なバージョンが必要です。 たとえば、ビデオの解像度と品質が5秒で​​さらに5秒のビデオをダウンロードできるようなものである場合、それが最適です。 ただし、3秒分のビデオをダウンロードするのに5秒かかる場合、プレーヤーは停止し、ストリームの次のチャンクがダウンロードされるのを待ちます。

一方、品質と解像度をさらに下げると、帯域幅が不必要に節約されるため、より高速な接続でのユーザーエクスペリエンスが低下するだけです。 ただし、3番目の方法があります。

アダプティブビットレートストリーミング

ユーザーごとに異なるバージョンのビデオをアップロードすることもできますが、その場合は、プレーヤーを制御し、接続とデバイスに最適なストリームを計算する機能が必要になります。 次に、プレーヤーはそれらを切り替える必要があります(たとえば、ユーザーが3GからWiFiに切り替える場合)。 それでも、クライアントがネットワークタイプを変更した場合はどうなりますか? 次に、プレーヤーは別のビデオに切り替える必要がありますが、最初からではなく、ビデオの途中で再生を開始する必要があります。 では、要求するバイト範囲をどのように計算しますか?

ビデオプレーヤーがネットワークタイプと利用可能な帯域幅の変化を検出し、最適なストリームが見つかるまで(同じビデオが異なる速度で準備されている)異なるストリームを透過的に切り替えることができれば、すばらしいでしょう。

それがまさにアダプティブビットレートストリーミングが解決するものです。

注:このHLSチュートリアルでは、暗号化、同期再生、およびIMSC1については説明しません。

HLSとは何ですか?

HTTPライブストリーミングは、2009年にAppleによって導入された適応型ビットレートストリーミングプロトコルです。m3u8ファイルを使用してメディアストリームを記述し、サーバーとクライアント間の通信にHTTPを使用します。 これは、すべてのiOSデバイスのデフォルトのメディアストリーミングプロトコルですが、AndroidおよびWebブラウザーで使用できます。

HTTPライブストリーミングのカバーイラスト

HLSストリームの基本的な構成要素は次のとおりです。

  1. M3U8プレイリスト
  2. さまざまなストリームのメディアファイル

M3U8プレイリスト

基本的な質問に答えることから始めましょう: M3U8ファイルとは何ですか?

M3U(またはM3U8)は、MP3ファイルのコレクションを整理するために元々作成されたプレーンテキストファイル形式です。 この形式はHLS用に拡張されており、メディアストリームの定義に使用されます。 HLSには、2種類のm3u8ファイルがあります。

  • メディアプレイリスト:ストリーミングに必要なファイルのURL(つまり、再生される元のビデオのチャンク)が含まれています。
  • マスタープレイリスト:メディアプレイリストへのURLが含まれ、メディアプレイリストには、異なる帯域幅用に準備された同じビデオのバリエーションが含まれます。

いわゆるM3U8ライブストリームURLは、https://s3-us-west-2.amazonaws.com/hls-playground/hls.m3u8などのM3U8ファイルへのURLにすぎません。

HLSストリームのサンプルM3U8ファイル

M3U8ファイルには、URLまたはローカルファイルパスのリストといくつかの追加のメタデータが含まれています。 メタデータ行は#で始まります。

この例は、単純なHLSストリームのM3U8ファイルがどのように見えるかを示しています。

 #EXTM3U #EXT-X-VERSION:3 #EXT-X-MEDIA-SEQUENCE:0 #EXT-X-ALLOW-CACHE:YES #EXT-X-TARGETDURATION:11 #EXTINF:5.215111, 00000.ts #EXTINF:10.344822, 00001.ts #EXTINF:10.344822, 00002.ts #EXTINF:9.310344, 00003.ts #EXTINF:10.344822, 00004.ts ... #EXT-X-ENDLIST
  • 最初の4行は、このM3U8プレイリストのグローバル(ヘッダー)メタデータです。
  • EXT-X-VERSIONは、M3U8形式のバージョンです( EXTINFエントリを使用する場合は、少なくとも3である必要があります)。
  • EXT-X-TARGETDURATIONタグには、各ビデオの「チャンク」の最大継続時間が含まれます。 通常、この値は約10秒です。
  • ドキュメントの残りの部分には、次のような行のペアが含まれています。
 #EXTINF:10.344822, 00001.ts

これはビデオの「チャンク」です。 これは、正確に10.344822秒の長さの00001.tsチャンクを表します。 クライアントビデオプレーヤーがビデオの特定のポイントからビデオを開始する必要がある場合、以前に表示されたチャンクの期間を合計することにより、要求する必要のある.tsファイルを簡単に計算できます。 2行目は、ローカルファイル名またはそのファイルへのURLにすることができます。

.tsファイルを含むM3U8ファイルは、HLSストリームの最も単純な形式であるメディアプレイリストを表します。

すべてのブラウザがデフォルトでHLSストリームを再生できるわけではないことに注意してください。

マスタープレイリストまたはインデックスM3U8ファイル

前のM3U8の例は、一連の.tsチャンクを指しています。 それらは元のビデオファイルから作成され、サイズ変更されてエンコードされ、チャンクに分割されます。

つまり、導入部で概説した問題がまだ残っているということです。非常に遅い(または異常に速い)ネットワーク上のクライアントについてはどうでしょうか。 または、画面サイズが非常に小さい高速ネットワーク上のクライアントですか? 光沢のある新しい電話でファイルをすべて表示できない場合は、ファイルを最大解像度でストリーミングしても意味がありません。

HSLのM3U8

HLSは、M3U8の別の「レイヤー」を導入することでこの問題を解決します。 このM3U8ファイルには、 .tsファイルへのポインターは含まれませんが、他のM3U8ファイルへのポインターが含まれ、特定のビットレートと解像度用に事前に準備されたビデオファイルが含まれます。

このようなM3U8ファイルの例を次に示します。

 #EXTM3U #EXT-X-STREAM-INF:BANDWIDTH=1296,RESOLUTION=640x360 https://.../640x360_1200.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=264,RESOLUTION=416x234 https://.../416x234_200.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=464,RESOLUTION=480x270 https://.../480x270_400.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=1628,RESOLUTION=960x540 https://.../960x540_1500.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=2628,RESOLUTION=1280x720 https://.../1280x720_2500.m3u8

ビデオプレーヤーは、次のような行のペアを選択します。

 #EXT-X-STREAM-INF:BANDWIDTH=1296,RESOLUTION=640x360 https://.../640x360_1200.m3u8

これらは、異なるネットワーク速度と画面解像度用に準備された同じビデオのバリアントと呼ばれます。 この特定のM3U8ファイル( 640x360_1200.m3u8 )には、 640x360ピクセルにサイズ変更され、 1296kbpsのビットレート用に準備されたビデオのビデオファイルチャンクが含まれています。 報告されるビットレートは、ビデオとビデオのオーディオストリームの両方を考慮に入れる必要があることに注意してください。

ビデオプレーヤーは通常、最初のストリームバリアントから再生を開始します(前の例では、これは640x360_1200.m3u8です)。 そのため、どのバリアントがリストの最初になるかを決定するために特別な注意を払う必要があります。 他のバリアントの順序は重要ではありません。

最初の.tsファイルのダウンロードに時間がかかりすぎる場合(「バッファリング」、つまり次のチャンクの待機が発生する)、ビデオプレーヤーはビットレートの小さいストリームに切り替わります。 そしてもちろん、それが十分に速くロードされた場合、それはそれがより良い品質のバリアントに切り替えることができることを意味しますが、それがディスプレイの解像度に意味がある場合に限ります。

インデックスM3U8リストの最初のストリームが最適でない場合、クライアントは適切なバリアントで解決するまで1〜2サイクル必要になります。

これで、HLSの3つのレイヤーができました。

  1. バリアントへのポインター(URL)を含むインデックスM3U8ファイル(マスタープレイリスト)
  2. さまざまな画面サイズとネットワーク速度のさまざまなストリーム用のバリアントM3U8ファイル(メディアプレイリスト) 。 これらには、.tsファイルへのポインター(URL)が含まれています。
  3. ビデオの一部を含むバイナリファイルである.tsファイル(チャンク)

ここでサンプルのインデックスM3U8ファイルを見ることができます(これもブラウザ/ OSによって異なります)。

場合によっては、クライアントが低速または高速のネットワーク上にあることを事前に知っていることがあります。 その場合、別の最初のバリアントを持つインデックスM3U8ファイルを提供することにより、クライアントが適切なバリアントを選択できるように支援できます。 これを行うには2つの方法があります。

  • 1つは、さまざまなネットワークタイプ用に複数のインデックスファイルを準備し、適切なものを要求するためにクライアントを事前に準備することです。 クライアントはネットワークタイプを確認してから、たとえばhttp://.../index_wifi.m3u8またはhttp://.../index_mobile.m3u8 //.../index_mobile.m3u8を要求する必要があります。
  • また、クライアントがhttpリクエストの一部としてネットワークタイプを送信し(たとえば、wifiまたはモバイル2G / 3G /…に接続されている場合)、リクエストごとにインデックスM3U8ファイルを動的に準備することもできます。 動的バージョンが必要なのはインデックスM3U8ファイルのみであり、単一ストリーム(バリアントM3U8ファイル)は静的ファイルとして保存できます。

HLS用のビデオファイルの準備

AppleのHTTPライブストリーミングには2つの重要な構成要素があります。 1つはビデオファイルの保存方法(後でHTTP経由で提供される)であり、もう1つはプレーヤー(ストリーミングクライアントアプリ)にどのビデオファイルを取得するかを指示するM3U8インデックスファイルです。

ビデオファイルから始めましょう。 HLSプロトコルは、ビデオファイルが同じ長さ(通常はそれぞれ10秒)の小さなチャンクに保存されることを想定しています。 元々、これらのファイルはMPEG-2 TSファイル( .ts )に保存し、MP3、HE-AAC、またはAC-3のオーディオを使用してH.264形式でエンコードする必要がありました。

HLSビデオ

つまり、30秒のビデオは、それぞれ約10秒の長さの3つの小さな.tsファイルに分割されます。

最新バージョンのHLSでは、断片化された.mp4ファイルも使用できることに注意してください。 これはまだ新しいことであり、一部のビデオプレーヤーはまだ実装する必要があるため、この記事の例では.tsファイルを使用します。

キーフレーム

チャンクは、各ファイルの先頭にキーフレームを使用してエンコードする必要があります。 各ビデオにはフレームが含まれています。 フレームは画像ですが、ビデオ形式では完全な画像が保存されないため、ディスク容量が多すぎます。 前のフレームとの違いだけをエンコードします。 ビデオの中間点にジャンプする場合、プレーヤーは、最初の画像を表示するためにこれらすべての差分を適用する場所から「開始点」を必要とし、次にビデオの再生を開始します。

そのため、 .tsチャンクの先頭にはキーフレームが必要です。 プレイヤーはチャンクの途中から始める必要がある場合があります。 プレーヤーは、最初のキーフレームからのすべての「差分」を追加することにより、常に現在の画像を計算できます。 ただし、開始から9秒で開始する場合は、9秒の「差分」を計算する必要があります。 その計算を高速化するには、数秒ごとにキーフレームを作成するのが最善です(最高のcca 3s)。

HLSブレークポイント

複数のビデオクリップを連続して再生したい場合があります。 これを行う1つの方法は、元のビデオファイルをマージしてから、そのファイルを使用してHLSストリームを作成することですが、これには複数の理由で問題があります。 動画の前後に広告を表示したい場合はどうなりますか? たぶん、あなたはすべてのユーザーのためにそれをしたくないでしょう、そしておそらくあなたは異なるユーザーのために異なる広告が欲しいでしょう。 そしてもちろん、事前に異なる広告を含むHLSファイルを準備する必要はありません。

この問題を修正するために、m3u8プレイリストで使用できるタグ#EXT-X-DISCONTINUITYがあります。 この行は基本的に、この時点から.tsファイルが異なる構成で作成される可能性がある(たとえば、解像度が変更される可能性がある)という事実に備えて事前に準備するようにビデオプレーヤーに指示します。 プレーヤーはすべてを再計算し、場合によっては別のバリアントに切り替える必要があり、そのような「不連続」ポイントに備える必要があります。

HLSを使用したライブストリーミング

「ビデオストリーミング」には基本的に2種類あります。 1つは、事前に録画され、ユーザーが決定したときにユーザーにストリーミングされるビデオのビデオオンデマンドVOD )です。 そして、ライブストリーミングがあります。 HLSはHTTPLiveStreamingの略語ですが、これまでに説明したことはすべてVODを中心にしていますが、HLSを使用してライブストリーミングを作成する方法もあります。

M3U8ファイルにいくつかの変更があります。 まず、バリアントM3U8ファイルに#EXT-X-MEDIA-SEQUENCE:1タグが含まれている必要があります。 次に、M3U8ファイルは#EXT-X-ENDLISTで終了してはなりません(そうでない場合は、常に最後に配置する必要があります)。

ストリームを記録している間、常に新しい.tsファイルがあります。 それらをM3U8プレイリストに追加する必要があり、新しいプレイリストを追加するたびに、 #EXT-X-MEDIA-SEQUENCE:<counter>のカウンターを1つ増やす必要があります。

ビデオプレーヤーはカウンターをチェックします。 前回から変更された場合、ダウンロードして再生する新しいチャンクがあるかどうかがわかります。 クライアントは新しいチャンクが再生されるのを待ってM3U8ファイルをリロードし続けるため、M3U8ファイルがキャッシュなしのヘッダーで提供されていることを確認してください。

VTT

HLSストリームのもう1つの興味深い機能は、Webビデオテキストトラック(VTT)ファイルをストリームに埋め込むことができることです。 VTTファイルはさまざまな用途に使用できます。 たとえば、Web HLSプレーヤーの場合、ビデオのさまざまな部分の画像スナップショットを指定できます。 ユーザーがビデオタイマー領域(ビデオプレーヤーの下)にマウスを移動すると、プレーヤーはビデオ内のその位置からスナップショットを表示できます。

VTTファイルのもう1つの明らかな使用法は、字幕です。 HLSストリームは、複数の言語に対して複数の字幕を指定できます。

 #EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-,NAME="English",DEFAULT=YES,AUTOSELECT=YES,FORCED=NO,LANGUAGE="en",CHARACTERISTICS="public.accessibility.transcribes-spoken-dialog, public.accessibility.describes-music-and-sound",URI="subtitles/eng/prog_index.m3u8"

次に、 theprog_index.m3u8は次のようになります。

 #EXTM3U #EXT-X-TARGETDURATION:30 #EXT-X-VERSION:3 #EXT-X-MEDIA-SEQUENCE:0 #EXT-X-PLAYLIST-TYPE:VOD #EXTINF:30, 0000.webvtt #EXTINF:30, 0001.webvtt ...

実際のVTT(たとえば0000.webvtt ):

 WEBVTT X-TIMESTAMP-MAP=MPEGTS:900000,LOCAL:00:00:00.000 00:00:01.000 --> 00:00:03.000 Subtitle -Unforced- (00:00:01.000) 00:00:03.000 --> 00:00:05.000 <i>...text here... -Unforced- (00:00:03.000)</i> <i>...text here...</i>

Appleは最近、VTTファイルに加えて、ストリーミング配信用に最適化された新しい字幕フォーマットであるIMSC1のサポートをHLSが特徴とすることを発表しました。 その最も重要な利点は、CSSを使用してスタイルを設定できることです。

HTTPライブストリーミングツールと潜在的な問題

Appleは、多くの便利なHSLツールを導入しました。これらのツールについては、公式のHLSガイドで詳しく説明されています。

  • ライブストリームの場合、Appleはmediastreamsegmenterという名前のツールを用意して、進行中のビデオストリームからその場でセグメントファイルを作成しました。
  • もう1つの重要なツールはmediastreamvalidatorです。 M3U8プレイリストをチェックし、ビデオファイルをダウンロードして、さまざまな問題を報告します。 たとえば、報告されたビットレートが.tsファイルから計算されたものと同じでない場合です。
  • もちろん、エンコード/デコード/マルチプレクサ/デマルチプレクサ/チャンク/ストリップ/マージ/結合/…ビデオ/オーディオファイルが必要な場合は、ffmpegがあります。 特定のユースケースに合わせて、独自のカスタムバージョンのffmpegをコンパイルする準備をしてください。

ビデオで最も頻繁に発生する問題の1つは、オーディオの同期です。 一部のHLSストリームの音声がビデオと同期していないことがわかった場合(つまり、俳優が口を開けたが、音声が数ミリ秒早いか遅いことに気付いた場合)、元のビデオファイルが撮影された可能性があります可変フレームレートを使用します。 必ず固定ビットレートに変換してください。

可能であれば、ソフトウェアが一定のフレームレートでビデオを録画するように設定されていることを確認することをお勧めします。

HTTPライブストリーミングの例

GoogleのExoPlayerプレーヤーを使用して事前定義されたHLSをストリーミングするHLSAndroidアプリケーションを準備しました。 ビデオとその下のHLS「イベント」のリストが表示されます。 これらのイベントには、ダウンロードされたすべての.tsファイル、またはプレーヤーがより高いまたはより低いビットレートストリームに切り替えることを決定するたびが含まれます。

ビューアの初期化の主要部分を見ていきましょう。 最初のステップでは、デバイスの現在の接続タイプを取得し、その情報を使用して、取得するm3u8ファイルを決定します。

 String m3u8File = "hls.m3u8"; ConnectivityManager connectivity = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetwork = connectivity.getActiveNetworkInfo(); if (activeNetwork != null && activeNetwork.isConnectedOrConnecting()) { int type = activeNetwork.getType(); int subType = activeNetwork.getSubtype(); if (type == ConnectivityManager.TYPE_MOBILE && subType == TelephonyManager.NETWORK_TYPE_GPRS) { m3u8File = "hls_gprs.m3u8"; } } String m3u8URL = "https://s3-us-west-2.amazonaws.com/hls-playground/" + m3u8File;

これは厳密には必要ではないことに注意してください。 HLSプレーヤーは、数チャンク後に常に正しいHLSバリアントに調整されますが、これは、最初の5〜20秒で、ユーザーがストリームの理想的なバリアントを視聴できない可能性があることを意味します。

m3u8ファイルの最初のバリアントは、ビューアが開始するバリアントであることを忘れないでください。 私たちはクライアント側にいて、接続タイプを検出できるので、少なくとも、この接続タイプ用に事前に準備されたm3u8ファイルを要求することで、最初のプレーヤーによるバリアント間の切り替えを回避することができます。

次のステップでは、HLSプレーヤーを初期化して起動します。

 Handler mainHandler = new Handler(); DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter.Builder() .setEventListener(mainHandler, bandwidthMeterEventListener) .build(); TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter); TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory); LoadControl loadControl = new DefaultLoadControl(); SimpleExoPlayer player = ExoPlayerFactory.newSimpleInstance(this, trackSelector, loadControl);

次に、プレーヤーを準備し、このネットワーク接続タイプに適したm3u8をフィードします。

 DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "example-hls-app"), bandwidthMeter); HlsMediaSource videoSource = new HlsMediaSource(Uri.parse(m3u8URL), dataSourceFactory, 5, mainHandler, eventListener); player.prepare(videoSource);

そしてここに結果があります:

AndroidでのHLSストリーミングの例

HLSブラウザの互換性、将来の開発

iOSでのビデオストリーミングアプリについては、ビデオが10分より長いか5 MBより大きい場合、HLSを使用する必要があるというAppleの要件があります。 それ自体が、HLSが存続することを保証するものです。 HLSとMPEG-DASHについていくつかの懸念があり、どちらがWebブラウザの分野で勝者になるかについての懸念がありました。 HLSは、すべての最新のブラウザーに実装されているわけではありません(前のm3u8 URLの例をクリックすると、おそらく気づいたでしょう)。 たとえば、Androidでは、4.0未満のバージョンではまったく機能しません。 4.1から4.4までは、部分的にしか機能しません(たとえば、オーディオが欠落している、またはビデオが欠落しているがオーディオは機能します)。

しかし、この「戦い」は最近少し単純になりました。 Appleは、新しいHLSプロトコルで断片化されたmp4ファイル( fMP4 )を許可すると発表しました。 以前は、HLSとMPEG-DASHの両方をサポートしたい場合は、ビデオを2回エンコードする必要がありました。 これで、同じビデオファイルを再利用し、メタデータファイル(HLSの場合は.m3u8 、MPEG-DASHの場合は.mpd )のみを再パッケージ化できるようになります。

もう1つの最近の発表は、高効率ビデオコーデック(HEVC)のサポートです。 使用する場合は、断片化されたmp4ファイルにパッケージ化する必要があります。 そしてそれはおそらくHLSの未来がfMP4であることを意味します。

ブラウザの世界の現在の状況では、 <video>タグの一部のブラウザ実装のみがHLSをすぐに再生できます。 しかし、HLS互換性を提供するオープンソースおよび商用ソリューションがあります。 それらのほとんどは、Flashフォールバックを使用してHLSを提供しますが、JavaScriptで完全に記述された実装がいくつかあります。

まとめ

この記事は特にHTTPライブストリーミングに焦点を当てていますが、概念的には、Adaptive Bitrate Streaming(ABS)がどのように機能するかについての説明として読むこともできます。 結論として、HLSは、ビデオストリーミングにおける多くの重要な問題を解決するテクノロジーであると言えます。

  • ビデオファイルの保存を簡素化します
  • CDN
  • さまざまなクライアント帯域幅を処理し、ストリームを切り替えるクライアントプレーヤー
  • 字幕、暗号化、同期再生、およびこの記事でカバーされていないその他の機能

最終的にHLSとMPEG-DASHのどちらを使用するかに関係なく、どちらのプロトコルも同様の機能を提供する必要があり、HLSにフラグメント化されたmp4(fMP4)を導入すると、同じビデオファイルを使用できます。 つまり、ほとんどの場合、両方のプロトコルの基本を理解する必要があります。 幸いなことに、それらは同じ方向に動いているように見えます。これにより、習得が容易になるはずです。