HLS とは
HLS(HTTP Live Streaming)は動画配信(ストリーミング配信)する際に使われるプロトコルです。Apple 社が開発しました。
まず Apple の公式を確認したい方はこちらからどうぞ
ストリーミング配信とダウンロード配信
動画データを一旦ダウンロードして再生するのがダウンロード配信です。
対してストリーミング配信は分割された動画データをダウンロードしながら再生し、不要になったら動画を見ているユーザーの PC から動画データが削除されるのがストリーミング配信です。
HLS の強み
HLS は 2025 年現在広く使われているストリーミングプロトコルです。
色々な強みがあるので整理してみます。
- 高速に配信できる(CDN が使えるため)
- アダプティブビットレートストリーミングに対応
- 色々なデバイスで再生可能
- ライブ配信にも使用可能
- プログラマブルに広告を挿入できたりします
いくつか掘り下げてみます。
高速配信
前述の通りデータの取り扱いに無駄がなく、かつ CDN という中継サーバにデータをキャッシュ(保存)できるため通信に関しても無駄を省く仕組みが利用できます。これによって高速に配信が可能になります。
アダプティブビットレートストリーミング
要は回線速度に応じて動画の画質を自動的に切り替える仕組みです。
アダプティブビットレートストリーミングとは、ユーザーのネットワーク状況に応じて最適なビットレートの動画を自動的に選択して再生する技術です。これにより、再生中にバッファリングが発生しにくくなり、快適な視聴体験が提供されます。
色々なデバイスで再生可能
HLS は HTTP プロトコルを使用しているため、PC やスマートフォン、タブレットなど、様々なデバイスで再生することができます。また HTTP の特性として NAT や FW などのネットワーク機器との相性が良いこともメリットとしてあるようです。
Safari とその他のブラウザでの再生方法の違い
Safari は Apple ということもあってか Safari 自体が HLS を解釈できます。実際、私も HLS を吐き出している時に Safari だけで再生できるという状況に遭遇しました。
では他のブラウザがどのように再生しているかというと video.js や hls.js などのライブラリと MSE というネットの仕組みを使用して再生させています。
HLS を扱う際にはこれらのことを頭の片隅に置いておくとトラブルシューティングに役立つかもしれません。
プログラムで広告を入れることも可能
動画サイトでよくある広告ですが、HLS ではああいったことも実現できます。動画の〇〇秒で〇〇の広告を表示させるということができるわけですね。
ファイル構成
mp4 などの動画ファイルを HLS に変換するといくつかのファイルが生成されます。大きく役割を分けると以下のようになります。
- マスタープレイリスト
- メディアプレイリスト
- メディアセグメント
マスタープレイリスト
xxxx.m3u8 というファイルです。m3u8 というファイルは複数あるのですが、多くの場合 video,audio,iframe という単語が入っていない m3u8 ファイルがマスターとなります。
マスターとは全体の設計図のようなものです。マスターから video.m3u8、audio.m3u8 を指定して呼び出します。
メディアプレイリスト
video.m3u8、audio.m3u8 といったメディアに関連するメディアセグメント(aac ファイルや ts ファイル)を呼び出すシナリオのようなものです。ちなみに iframe.m3u8 というものは早送り、巻き戻し、プレビューサムネイル表示といったトリックプレイ機能のために利用されるプレイリストです。
メディアセグメント
実際の動画や音声のデータを含む分割された(1ファイルにすることも可能)小さなファイルです。メディアセグメントは基本的にバイナリ形式です。ツールをつかって開くと以下のように記述されています。
※あくまでもイメージです。
00000000: fff1 4c80 2aa2 5421 2001 e83d 1bff c000 ..L.\*.T! ..=....
00000010: 0000 0000 0000 0000 0000 0000 0000 0000 ................
00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
・
・
・
実際に表示する際は ffprobe コマンドなどで表示できます。
プレイリスト内のタグ
プレイリストの m3u8 ファイルはテキストが書かれているだけなのでとても軽量かつテキストエディタで開くことができます。そこには HLS のタグが色々と書かれているので確認していきましょう。
HLS のタグは基本的に#EXT から行頭で指定します。主に私が使用しているもの(ブラウザ+ video.js で再生するための HLS)を中心にまとめています。
属性に関してもかなり多いのでここには書いていないものもあります。記載がないものに関しては適宜 RFC8216 をご確認することをお勧めいたします。
EXTM3U
これはファイルがプレイリストであることを示すタグになります。
master.m3u8 で使われていたタグ
EXT-X-MEDIA
EXT-X-MEDIA は複数音声(例えば日本語、英語など)、字幕、複数動画トラック(スポーツ中継などの違う角度からの映像など)を制御する、関連づけるために使用されます。
以下 EXT-X-MEDIA にはいくつかのルールがあります。
-
EXT-X-MEDIA タグはマスタープレイリスト内で、EXT-X-STREAM-INF タグが記述される前に必ず配置する必要があります。
EXT-X-STREAM-INF タグには、AUDIO、SUBTITLES、CLOSED-CAPTIONS などの属性があり、これらは EXT-X-MEDIA タグの GROUP-ID 属性を参照します。このため、プレーヤーが EXT-X-STREAM-INF タグを解析する前に、参照先の EXT-X-MEDIA タグがすでに定義されていなければなりません 。 -
同じグループ内での全ての EXT-X-MEDIA タグは異なる名前を持つ必要があります。
-
EXT-X-STREAM-INF タグに RESOLUTION(解像度)と VIDEO(動画)の両方の属性がある場合、その動画ストリームに紐づけられているすべての代替動画(アプセルの動画など)は、RESOLUTION で指定された解像度と全く同じ解像度を持っていなければなりません。
-
EXT-X-STREAM-INF に関連付けられたすべての代替表現(Rendition)は、Variant Stream の制約を満たさなければなりません。規約とは「同一のコンテンツであること」「同期が取れていること」になります。
TYPE
オーディオ、ビデオ、字幕、クローズドキャプション(視覚障害者向けの補助情報、例えば悲しい音楽や、雷鳴の効果音など)のいずれかを文字列で指定します。
URI(任意)
メディアプレイリストファイルを指定します。指定は文字列を引用府で囲って指定します。
※TYPE 属性がクローズドキャプションの場合は URI が存在してはならないというルールがあります。
GROUP-ID(必須)
AUDIO 属性と同じ値を設定してどのオーディオグループを使用するかを設定します。文字列を引用府で囲って指定します。
LANGUAGE(任意)
言語を指定します。文字列を引用府で囲って指定します。
以下は英語の例です。
LANGUAGE="eng"
NAME(必須)
人間が読める文字列を引用府で囲って指定します。この時 LANGUAGE 属性で指定した言語で記述します。
AUTOSELECT(任意)
YES か NO の文字列で指定します。利用する音声や字幕を自動的に選択する場合は YES、ユーザーが決定する場合は NO を設定します。
DEFAULT(任意)
YES か NO の文字列で指定します。この値を YES にすると、その設定された動画は最初に再生されるものとなります。NO の場合はユーザーに選ばれるまでは再生されるリストに入りません。
CHANNELS(必須・任意)
音声のステレオ、5.1 サラウンドなどを切り替えます。チャンネルが複数ある場合は必須となりますが、一つしかない場合は任意となります。ステレオは"2"、5.1 は"6"といった具合に引用府で囲って指定します。
EXT-X-STREAM-INF
バリアントストリーム、要はネットワーク状況で解像度を切り替える仕組みのことです。それを制御するタグになります。なのでマスタ m3u8 ファイル内に複数記述されることもあります。
以下は EXT-X-STREAM-INF の属性になります。この属性は EXT-X-I-FRAME-STREAM-INF という属性でも引き継がれて使われます。
URI(必須)
I-frame プレイリストファイルへの URL を指定します。この URL で示されるプレイリストは、#EXT-X-I-FRAMES-ONLY タグを含む必要があります 。
BANDWIDTH(必須)
I-frame プレイリストのピークビットレート(bits per second)を指定します。この値は、プレーヤーがネットワーク状況に応じて適切な I-frame ストリームを選択するために使用されます 。
AVERAGE-BANDWIDTH(任意)
ビットレートの平均を 10 進整数で指定します。この値が不正確な場合再生が停止したり、再生できない現象が発生する可能性があります。その際は任意の属性なので一旦削除してテストしてみるのも一つの方法かもしれません。
CODECS
I-frame プレイリストに含まれるメディアセグメントのコーデックを指定します 。この情報は、プレーヤーが正しいデコーダーを準備するために不可欠です。
RESOLUTION
I-frame ストリームの解像度を指定します。
FRAME-RATE(任意)
フレームレート(1秒間に何枚写真が表示されるか)を設定します。10 進浮動小数点数で指定します。
AUDIO(任意)
この属性でどの音声グループを使用するかを指定します。この値は Master Playlist 内の別の場所にある EXT-X-MEDIA タグの GROUP-ID 属性と一致しなければなりません。
AWS MediaConvert の JSON 設定では AudioRenditionSets でこの AUDIO を設定し、AudioGroupId で GROUP-ID 属性を設定します。
PROGRAM-ID(バージョン6で削除)
RFC にはバージョン6で削除とだけ書かれていました。このタグがどんな役割かどなたかご存知でしたらぜひコメントお願いいたします。
EXT-X-I-FRAME-STREAM-INF
このタグは I-frame 専用のタグです。トリックプレイをする際に使用します。
具体的には再生バーのシーク時にプレビュー画面を表示するといった場面に利用されます。
必須タグとして URI、BANDWIDTH が必須となります。以下主要なタグも解説しますがこれ以外にも EXT-X-STREAM-INF がもつ属性が使えるようです。
このタグが使われている m3u8 ファイルでブラウザ(Chrome、Firefox、opera、Safari)+ video.js でシークの動作が実現できています。
以下 EXT-X-I-FRAME-STREAM-INF の属性は基本的に EXT-X-STREAM-INF の属性を引き継ぎます。
EXT-X-INDEPENDENT-SEGMENTS
このタグを指定することで全てのセグメントが独立して単独でデコードできるようになることを示します。それによってシーク操作(タイムラインで10秒の地点にジャンプするといった操作)がやりやすくなったりします。
iframe.m3u8、Video.m3u8、Audio.m3u8 で使われていたタグ
トリックプレイに関連するプレイリスト iframe.m3u8 で使われていたタグになります。
EXT-X-VERSION(必須)
このタグはプレイリストファイルとその関連メディアおよびサーバーの互換バージョンを示し、プレイリスト全体に適用されます。バージョン番号は整数で指定します。
※このタグはプレイリストに複数含めると解析に失敗します。
EXT-X-MEDIA-SEQUENCE
このタグはプレイリスト内の最初のメディアセグメントのシーケンス番号を指定します。このタグが存在しないときは最初のメディアセグメントの番号は 0 になります。番号は 10 進数の整数で指定します。
※EXT-X-MEDIA-SEQUENCE タグはメディア(.ts などのメディアファイルの記述)の前に出現する必要があります。
EXT-X-ALLOW-CACHE
このタグも RFC8216 にバージョン7で削除されという記述があるのみでした。
EXT-X-TARGETDURATION
このタグはメディアセグメントの最大長を秒単位(10 進整数)指定、つまり EXTINF タグで指定されている各セグメントの長さはこのターゲット期間以下でなければなりません。
EXT-X-I-FRAMES-ONLY
このタグはプレイリスト全体に適用されトリックプレイに使用されます。プレイリスト内の各メディアセグメントが他のフレームに依存しないことを表し、これによってトリックプレイが可能になります。
※EXT-X-I-FRAMES-ONLY を使用するには EXT-X-VERSION の値が 4 以上のバージョンが必要です。
EXTINF
このタグはメディアセグメントの長さを指定します。このタグの指定は以下のようにします。
#EXTINF:<duration>,[<title>]
具体的には以下のように指定します。
#EXTINF:3.0,
#EXT-X-BYTERANGE:57528@1193236
test-sample_Video.ts
#EXTINF:3.0000000000000018,
#EXT-X-BYTERANGE:69936@1501932
test-sample_Video.ts
duration
duration はメディアセグメントの長さを秒単位(整数、または浮動小数点)で指定します。
title
これは人が読むための属性で任意の値を設定できます。前述の具体例では title が省略された形で記載されています。EXT-X-BYTERANGE が title ではなくタグとして次の行に写っていることにご注意ください。
EXT-X-BYTERANGE
このタグでどのメディアファイルからデータを読み込むかを URI で識別します。そして「どの位置」から「どのくらいのデータ量」を読み込むかを指定します。
#EXT-X-BYTERANGE:<n>[@<o>]
n も o もバイト単位(10 進整数)で指定します。
n はデータの長さ、o はデータの開始位置のバイトを示しています。
#EXTINF:3.0,
#EXT-X-BYTERANGE:57528@1193236
test-sample_Video.ts
#EXTINF:3.0000000000000018,
#EXT-X-BYTERANGE:69936@1501932
test-sample_Video.ts
上記であれば
test-sample_Video.ts の 1193236 の位置から 57528 分読み込み
次に 1501932 の位置から 69936 分読み込むという形になります。
ここで一つ気になるのがデータが連続して保存されていないということですね。このようにデータが断片化されて読み込まれており、シーク操作の際はこの EXT-X-BYTERANGE で指定されている単位でデータが読み込まれているようです。
o が省略されたらそれは前の EXT-X-BYTERANGE のデータの終わりから読み込む、つまりデータが連続した形で保存されています。
※エラーになるケース:o が省略され、かつそれ以前に EXT-X-BYTERANGE の記述がない場合はエラーとなります。
EXT-X-ENDLIST
このタグが出てきたらプレイリストにこれ以上メディアセグメントが追加されないということを示しています。
このタグはメディアプレイリストファイルのどこに書いても問題ありません。
EXT-X-PLAYLIST-TYPE
プレイリストのタイプ、ライブ配信なのか、オンデマンド配信なのかを設定します。
EVENT または VOD(ビデオオンデマンド)のテキストで設定します。
EVENT を設定すると新しいセグメントはプレイリストの最後に追加されるようになるようです。
VOD ではプレイリストが静的になり変更されないようです。
CMAF とは
HLS を説明してきましたが、MPEG-DASH というものもあります。そしてざっくりと以下の特徴があります。
- HLS:古い Apple デバイスにも対応できる。音声ファイルの拡張子は.ts
- MPEG-DASH:幅広いデバイスに対応できる。音声ファイルの拡張子は.m4s
そして CMAF という形式を採用すると HLS と MPEG-DASH の両方に対応して再生ができます。
私のケースでは以下の理由から CMAF をしばらく採用してみることにしました。
- AWS MediaConvert で CMAF と従来の HLS が両方吐き出せた
- コストを計算してもそこまで違いがなかった
- 今後は CMAF がスタンダードになりそうと AI から聞いた
- 想定している再生環境でどちらも再生、シーク操作などができた
∟OS:iOS,Android,Windows,MacOS
∟ ブラウザ:Chrome,Firefox(Android のぞく),Opera,Safari(Windows,Android のぞく),Edge
CMAF と従来の HLS での違いとして CMAF は iOS 10.0、macOS 10.12、tvOS 10.0 以前の環境ではサポートされない可能性があるようです。なのでほとんどの場合では CMAF で問題ないと考えても良いでしょう。
あとがき
今回改めて HLS の動画形式をブラウザで再生してみましたが、ブラウザごとにまだまだ差異があることがわかりました。HLS 自体 Apple の技術ということもあり、やはり iPhone、Safari でのシークや再生のスムーズさは突出していました。Safari 以外では再生できないというバグにも遭遇したのも印象深かったです。
参考ページ
上記ページを参考にして書きましたが一部AIに読み解いてもらった部分もあるのでもし間違いがあればコメントいただけると嬉しいです。
Discussion