こんにちは、メディアプラットフォーム事業部 プラットフォーム技術部の新井です。
メディアプラットフォーム事業部から名前が変わり、プラットフォーム技術部になりました。過去のメディアプラットフォーム事業部の記事はこちらです。
今回の記事では動画配信の会社らしく、ストリーミング配信のプロトコルの一つである HLS について書いていこうと思います。
HLSとは
「HLSとは」みたいな記事はたくさん書かれていますが、まずはざっくりとした説明から始めます。
HLS (HTTP Live Streaming)は、Appleによって開発されたストリーミング配信を行うためのプロトコルで、m3u8と呼ばれるマニフェストファイルを用いて、小さなセグメントに分割された動画データを配信することで動画の再生を行うことができます。
セグメントは分割された動画データのため、一つ一つのダウンロードが早く、視聴者は待機時間が少なく再生を開始することができます。
また一時的なネットワークの不調でセグメントの再取得を行う必要があった場合も、短いバッファリングで済ませることができます。
まず、マニフェストファイルについて簡単な説明をします。
マルチバリアントプレイリスト(Multivariant Playlist)*1はメディアプレイリストを列挙したファイルで、メディアプレイリストというのはセグメントファイル(動画データ)を列挙したファイルです。
この記事では以降、マルチバリアントプレイリスト、メディアプレイリストをまとめて、マニフェストと記載します。
このメディアプレイリストの中には小さく分割されたセグメントファイル(動画データ)のURLが含まれており、プレイヤーは、これらのセグメントファイルを順番にダウンロードして再生します。再生までの流れは次の通りです。
- 解像度等が異なるストリームを複数含むマルチバリアントプレイリストを取得する
- 通信速度等の状況を元にストリームを選択し、そのメディアプレイリストを取得する
- メディアプレイリストに記載されたURLからセグメントファイルをダウンロードする
- セグメントファイルを再生する
メディアプレイリストの中には複数のセグメントファイルのURLが含まれているので、3と4は複数回行われます。
1で取得するマルチバリアントプレイリストは次のような内容です。
#EXT-X-STREAM-INF
タグが複数あり、このマルチバリアントプレイリストには1280x720, 960x540, 640x360 の3つの解像度が含まれていることがわかりますね。RESOLUTIONの部分です。これは動画を見る時プレイヤーによくある画質設定の高、中、低に対応しています。
Multivariant Playlist
#EXTM3U #EXT-X-VERSION:3 #EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="SUB",NAME="日本語",DEFAULT=NO,AUTOSELECT=NO,LANGUAGE="ja",URI="https://www.example.com/subtitles.m3u8" #EXT-X-IMAGE-STREAM-INF:BANDWIDTH=21506,CODECS="jpeg",RESOLUTION=192x108,URI="https://www.example.com/images.m3u8" #EXT-X-STREAM-INF:BANDWIDTH=1091244,AVERAGE-BANDWIDTH=787916,CODECS="avc1.4D401E,mp4a.40.2",RESOLUTION=640x360,CLOSED-CAPTIONS=NONE,SUBTITLES="SUB",FRAME-RATE=29.970 https://www.example.com/manifest_1.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=2382397,AVERAGE-BANDWIDTH=1595264,CODECS="avc1.64001F,mp4a.40.2",RESOLUTION=960x540,CLOSED-CAPTIONS=NONE,SUBTITLES="SUB",FRAME-RATE=29.970 https://www.example.com/manifest_2.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=3859904,AVERAGE-BANDWIDTH=2519193,CODECS="avc1.64001F,mp4a.40.2",RESOLUTION=1280x720,CLOSED-CAPTIONS=NONE,SUBTITLES="SUB",FRAME-RATE=29.970 https://www.example.com/manifest_3.m3u8
2で取得するメディアプレイリストは次のような内容です。
#EXTINF
の次の行に書かれているのがセグメントファイルのURLです。4秒のtsファイルが3つ分、計12秒分のtsファイルが書かれていますね。
このそれぞれのtsファイルをダウンロードして再生することで私たちは動画を視聴することが出来ています。
Media Playlist
#EXTM3U #EXT-X-VERSION:6 #EXT-X-TARGETDURATION:5 #EXT-X-MEDIA-SEQUENCE:1 #EXT-X-DISCONTINUITY-SEQUENCE:1 #EXT-X-KEY:METHOD=AES-128,URI="https://www.example.com/key",IV=0x00000000000000000000000000801650,KEYFORMAT="identity",KEYFORMATVERSIONS="1" #EXT-X-PROGRAM-DATE-TIME:2023-01-01T00:00:00.000Z #EXTINF:4.004, https://www.example.com/manifest_1_1.ts #EXT-X-KEY:METHOD=AES-128,URI="https://www.example.com/key",IV=0x00000000000000000000000000801651,KEYFORMAT="identity",KEYFORMATVERSIONS="1" #EXT-X-PROGRAM-DATE-TIME:2023-01-01T00:00:04.000Z #EXTINF:4.004, https://www.example.com/manifest_1_2.ts #EXT-X-KEY:METHOD=AES-128,URI="https://www.example.com/key",IV=0x00000000000000000000000000801652,KEYFORMAT="identity",KEYFORMATVERSIONS="1" #EXT-X-PROGRAM-DATE-TIME:2023-01-01T00:00:08.000Z #EXTINF:4.004, https://www.example.com/manifest_1_3.ts
以上がざっくりとした説明です。
しかし、#EXT-X-IMAGE-STREAM-INF
だったり #EXT-X-KEY
だったりとよくわからないタグがたくさんあると思います。
そこで、このブログではこれらHLSの各タグについてRFC 8216に基づいて網羅的に解説をしていきます。HLSのマニフェストを読むのが趣味、という人の一助になれば幸いです。
共通タグ
マルチバリアントプレイリスト、メディアプレイリストの両方で使用できます。
#EXTM3U
M3UファイルがHLS形式(HLSプレイリスト)であることを示すタグです。
このタグはマニフェストの先頭に書く必要があります。
#EXTM3U
#EXT-X-VERSION
HLSプロトコルのバージョンを明示的に指定するタグです。
複数の #EXT-X-VERSION
タグを一つのマニフェストに含めることはできません。
これを用いることで、クライアントにHLSプロトコルのバージョンを伝えることができます。
HLSプロトコルのバージョン1と互換性のないタグをマニフェストに含む場合は、対応しているバージョンを指定する必要があります。
例えば、#EXTINF
に小数点を入れる場合は3以上を指定する必要があります。*2
#EXT-X-VERSION:<version>
マルチバリアントプレイリストのタグ
ストリームに関するタグです。
マルチバリアントプレイリストのタグはメディアプレイリストに含めることができません。
#EXT-X-MEDIA
追加の音声や字幕を指定するためのタグです。
このタグによってプレイヤーで音声を変更したり、字幕を変更したりすることができるようになります。
GROUP-ID
で #EXT-X-STREAM-INF
タグの AUDIO
や VIDEO
、SUBTITLES
と結びつきます。
#EXT-X-MEDIA:TYPE=<type>,GROUP-ID="<ID>",NAME="<name>",LANGUAGE="<language>",DEFAULT=<NO or YES>,AUTOSELECT=<NO or YES>,URI="<url>"
#EXT-X-STREAM-INF
動画のストリームのメディアプレイリストを指定するためのタグです。
このタグはビットレートや解像度についての属性を持っており、マルチバリアントプレイリストに複数持つことでマルチビットレートストリーミングを行うことができます。
クライアントはこの情報を使用して最適なストリームを選択しています。
また、このタグには CLOSED-CAPTIONS
や SUBTITLES
といった字幕に関する属性も含んでいます。
CLOSED-CAPTIONS=NONE
とすると、Appleのプレイヤーで"Unknown CC"を表示しないようにすることができます。*3
属性については例で示しているもの以外にも存在します。必要に応じて利用してください。
#EXT-X-STREAM-INF:BANDWIDTH=<bandwidth>,AVERAGE-BANDWIDTH=<average segment bit rate>,RESOLUTION=<width>x<height>,CODECS="<codecs>",CLOSED-CAPTIONS="<NONE or type>",SUBTITLES="<ID>",FRAME-RATE=<frame rate>,AUDIO="<audio-id>",VIDEO="<video-id>" <url>
#EXT-X-IMAGE-STREAM-INF
静止画像のストリームのメディアプレイリストを指定するためのタグです。
実はAppleのドキュメントにはこのタグは存在していません。
このタグを利用することで、プレイヤーでコンテンツの巻き戻しや早送り(トリックプレイ再生)を行った際に画像を表示することができます。
なお、#EXT-X-I-FRAME-STREAM-INF
タグを使用しても同様のことができますが、#EXT-X-IMAGE-STREAM-INF
タグではI-frameを使用せず適切にリサイズされた画像を使用したり、複数の画像をタイル状に並べた画像を使用したりできるので、ネットワーク帯域幅を節約することができます。
#EXT-X-IMAGE-STREAM-INF:BANDWIDTH=<bandwidth>,CODECS="<codecs>",RESOLUTION=<width>x<height>,URI="<url>"
メディアプレイリストのタグ
メディアプレイリスト設定を示すタグです。
各タグを複数含めることはできません。また、マルチバリアントプレイリストに含めることもできません。
#EXT-X-TARGETDURATION
セグメントの最大再生時間(秒)を指定するダグです。
セグメントの秒数を4秒と設定していてもエンコード等の関係で、4.004秒等になる場合があります。そのため、こちらには5秒のようにセグメントよりも大きい値を指定する必要があります。*4
#EXT-X-TARGETDURATION:<seconds>
#EXT-X-MEDIA-SEQUENCE
ストリームの最初のセグメントが全体の中の何番目かを示すタグです。
クライアントはこのタグを用いてセグメントを一意に特定することができ、ライブ配信においては新たに取得する必要があるセグメントを判断することができます。
#EXT-X-MEDIA-SEQUENCE:<sequence>
#EXT-X-DISCONTINUITY-SEQUENCE
ストリームが不連続となった回数を示すタグです。
初期値は0であり、ストリームの切り替えやPTSの変更など、ストリームが不連続となるたびに1ずつ増加します。
#EXT-X-DISCONTINUITY-SEQUENCE:<sequence>
#EXT-X-ENDLIST
これ以上セグメントがないことを示すタグです。
つまりメディアプレイリストの終わりを示しています。
#EXT-X-ENDLIST
#EXT-X-PLAYLIST-TYPE
メディアプレイリストがVODのものかLIVEのものか示すためのタグです。
VOD
または EVENT
を指定することができます。
VOD
を指定した場合はメディアプレイリストを変更できません。EVENT
を指定した場合はメディアプレイリストの最後にセグメントを追加することができます(DVRが有効なライブ配信)。
また、このタグを省略した場合は上記の制限はなくなり、追加と削除が可能になります。
#EXT-X-PLAYLIST-TYPE:<VOD or EVENT>
メディアセグメントのタグ
セグメントファイルに関するタグです。
マルチバリアントプレイリストに含めることはできません。
#EXTINF
セグメントの再生時間とファイルのURLを指定するタグです。 HLSプロトコルのバージョンが3未満の場合は秒数を整数で指定する必要があります。
#EXTINF:<seconds>,<title> <url>
#EXT-X-DISCONTINUITY
前後のセグメントが不連続であることを示すタグです。
このタグを用いることで、別々にエンコードした複数の動画を1つの動画として配信できます。
こちらの記事でも説明されています。ぜひお読みくださいませ。
developers.play.jp
#EXT-X-DISCONTINUITY
#EXT-X-KEY
暗号化された配信であることを示していて、復号のために必要な情報を持つタグです。
このタグを使用することでAES-128などの暗号化キーを取得することができます。
暗号化に使用される初期化ベクトル(IV)や、暗号化キーの形式とバージョンを指定するための KEYFORMATVERSIONS
属性を持っています。
#EXT-X-KEY:METHOD=<method-name>,URI="<url>",IV=<iv-value>,KEYFORMAT="<key-format>",KEYFORMATVERSIONS="<key-format-versions>"
#EXT-X-PROGRAM-DATE-TIME
セグメントの絶対的な時間を示すタグです。
プレイヤーがシーク等をする際にこちらのタグを用いるよう実装することができます。
#EXT-X-PROGRAM-DATE-TIME:<YYYY-MM-DDThh:mm:ssZ>
メディアメタデータのタグ
プレイリストに関する情報を示すタグです。
特定のメディアセグメントに紐づくタグではありません。
#EXT-X-DATERANGE
開始時間と終了時間を持つメタデータを示すタグです。
例えば、広告挿入の開始時間と終了時間、SCTE35-OUT
属性などを持たせることができます。
これを利用してserver-side ad insertion (SSAI)を行うことができます。
#EXT-X-DATERANGE:ID="<id>",START-DATE="<YYYY-MM-DDThh:mm:ssZ>",PLANNED-DURATION=<seconds>,SCTE35-OUT=<scte35>
まとめ
これらのタグを用いることでHLSで動画配信を行うことができ、HLSで動画配信を行っている場合はこれらのタグを使っています。
HLSのタグについてはまだ上記以外にもありますが、代表的なものについては記載できたかと思います。
HLSの中身が読めると、動画が再生できない時の原因特定の手掛かりになったりと、良いことは多いです。
今回記載したくらいの簡単なものでいいので、HLSの各タグが何を意味しているのかを知っておくとよいと思います。*5
*1:Apple公式では "Multivariant Playlist", RFC 8216では "Master Playlist" とされています。
*2:参考: EXT-X-VERSION RFC 8216 - HTTP Live Streaming
*3:参考: https://docs.theoplayer.com/faq/26-how-to-remove-unwanted-cc-track-ios-safari.md
*4:HLSプロトコルのバージョン6以降では、セグメントの秒数の最大値ではなく、セグメントの秒数を四捨五入した値の最大値を指定できます。
*5:色々なサービスのマニフェストも読めるようになるので楽しいです。