コンテンツへスキップ
Tony

HLS プロトコル入門

HLS プロトコルの基本的な仕組み、エンコードフロー、ファイル形式、再生モード、セキュリティ、プッシュ配信、およびトラブルシューティングを解説します。

テクノロジー , 音声動画 3 分で読めます

HLSHTTP Live Streaming の略で、Apple が提唱する HTTP ベースのストリーミングネットワーク転送プロトコルです。ライブ配信とオンデマンド配信の両方をサポートし、マルチビットレート、音声・動画のデュアルトラック、字幕などの機能も備えています。その仕組みは、1本の動画を複数の小さな動画セグメントに分割し、それらの断片をつなぎ合わせて再生を実現するというものです。 HLS プロトコルの仕様は以下のとおりです。

  • 動画のコンテナフォーマットは TS です。
  • 動画のコーデックは H264、音声のコーデックは MP3AAC、または AC-3 です。
  • TS 動画ファイル自体に加えて、再生を制御するための m3u8 ファイル(テキストファイル)も定義されています。

長所:

  1. 特殊な状況下でのファイアウォールによるブロックを回避できる
  2. サーバーの拡張が容易。RTMP はステートフルなプロトコルであるため、再生中の各クライアントの状態を維持する必要があり、動画サーバーをスムーズに拡張するのが難しい。一方 HLS はステートレスなプロトコル(HTTP)に基づいており、クライアントはサーバーに保存された通常の TS ファイルを順番にダウンロードして使用するだけなので、負荷分散は通常の HTTP ファイルサーバーの負荷分散と同様にシンプルである
  3. ビットレート自适应(ABR)

短所:

  1. ライブ配信シナリオにおける高い遅延(録画配信には遅延の影響なし)
  2. 大量の TS セグメントファイルがサーバーのストレージとリクエストに負荷をかける

HLSHLS ライブ配信フロー

  • AVInputs

音声・動画ソースの取り込み

  • Server

サーバーコンポーネントは入力されたメディアストリームを取得し、メディアエンコーダで MPEG-4H.264 ビデオと AAC オーディオ)形式にエンコードした後、ハードウェアで MPEG-2(MPEG-2 transport stream)トランスポートストリームにパッケージ化します。図に示されているように、トランスポートストリームは stream segmenter を通過し、ここで MPEG-2 トランスポートストリームが小さな断片に分割され、1つまたは複数のシリーズの .ts 形式のメディアファイルとして保存されます。この処理には Apple stream segmenter などのエンコードツールが必要です。 動画は fMP4 ファイル(新版)または ts ファイル(旧版)となり、音声のみの場合は通常 ADTS ヘッダー付きの AACMP3、または AC-3 形式の小さな音声セグメントにエンコードされます。

サーバー側ではハードウェアエンコードとソフトウェアエンコードの2つの方式があり、どちらも上記のルールに従って既存のメディアファイルをセグメント化し、インデックスファイルで管理する機能を提供します。ソフトウェアによるセグメント化には、通常 Apple 社が提供するツールまたはサードパーティの統合ツールが使用されます。

  • Distribution

HTTP サービスを提供し、Server で作成された m3u8 インデックスと ts セグメントファイルを配信します。

  • Clients m3u8 リソースをリクエストします。

HLS プロトコルには、インデックスファイルと ts/fMP4 ファイルの2種類のファイルが含まれます。

以下の2種類があります。

  1. Index file
  2. Alternate Index file

HLS_IndexHLS Index

ts ファイルは複数の ts packet で構成され、各 ts packet188 バイトです。 理由:ATM(Asynchronous Transfer Mode) システムに適合させるため。

is motivated by the fact that the payload of the ATM Adaptation Layer-1 (AAL-1) cell is 47 bytes. Therefore, four AAL-1 cells can accommodate a single TS packet.

HLS_TSHLS TS

HLS_fMP4HLS fMP4 EXT-X-VERSION 7fMP4 がサポートされました。 fMP4MPEG-4 Part 12 に基づくストリーミングメディア形式で、mp4 と非常に似ていますがいくつかの違いもあります。fMP4 はストリーミング再生のニーズにより適しています。 fMP4h.265 をサポートしており、帯域幅を大幅に節約できるため、特に映像監視の分野で現在の動画の主流になりつつあります。

  1. オンデマンド配信(VOD) 現在の時点ですべての index ファイルと ts ファイルを取得できます。2次 index ファイルにはすべての ts ファイルのアドレスが記録されています。このモードでは、クライアントはすべてのコンテンツにアクセスできます。上記の例は、オンデマンド配信モードにおける m3u8 の構造です。

  2. ライブ配信 M3U8ts ファイルがリアルタイムで生成されます。インデックスファイルは常に動的に変化するため、再生時には継続的に2次 index ファイルをダウンロードして、最新の ts ファイルを取得して動画を再生する必要があります。2次 index ファイルの末尾に #EXT-X-ENDLIST マークがない場合、それは Live 動画ストリームであることを示します。

暗号化情報:#EXT-X-KEY:METHOD=AES-128,URI=“xx.key”,IV=xxx

FairPlay Streaming

FairPlay Streaming is:

  • A secure key delivery mechanism Content Key is protected on the network and on the client during playback
  • Key delivery is transport agnostic Easy to integrate with existing key server infrastructure
  • Requires protected HDMI for external output

フロー HLS_fair_playHLS Fair Play

Conceptually, HTTP Live Streaming consists of three parts: the server component, the distribution component, and the client software. In a typical configuration, a hardware encoder takes audio-video input, encodes it as HEVC video and AC-3 audio, and outputs a fragmented MPEG-4 file or an MPEG-2 transport stream. A software stream segmenter then breaks the stream into a series of short media files, which are placed on a web server. The segmenter also creates and maintains an index file containing a list of the media files. The URL of the index file is published on the web server. Client software reads the index, then requests the listed media files in order and displays them without any pauses or gaps between segments.

ダウンロード先: https://developer.apple.com/download/all/?q=HLS

インストール後、goexample があることを確認 HLS_go_serverHLS Go Server brew install gogo をインストールし、サービスを起動します。

Terminal window
# tony @ tonyMBP in ~/Desktop/hls_server [14:48:18]
$ go run ll-hls-origin-example.go
ll-hls-origin-example.go:43:2: no required module provides package github.com/fsnotify/fsnotify: go.mod file not found in current directory or any parent directory; see 'go help modules'
# tony @ tonyMBP in ~/Desktop/hls_server [14:48:25] C:1
$ go mod init hls_server
go: creating new go.mod: module hls_server
go: to add module requirements and sums:
go mod tidy
# tony @ tonyMBP in ~/Desktop/hls_server [14:49:23]
$ go build
ll-hls-origin-example.go:43:2: no required module provides package github.com/fsnotify/fsnotify; to add it:
go get github.com/fsnotify/fsnotify
# tony @ tonyMBP in ~/Desktop/hls_server [14:49:28] C:1
$ go get github.com/fsnotify/fsnotify
go: downloading github.com/fsnotify/fsnotify v1.5.4
go: downloading golang.org/x/sys v0.0.0-20220412211240-33da011f77ad
go: added github.com/fsnotify/fsnotify v1.5.4
go: added golang.org/x/sys v0.0.0-20220412211240-33da011f77ad
# tony @ tonyMBP in ~/Desktop/hls_server [14:49:48]
$ go run ll-hls-origin-example.go
Listening on http://:8443/

Terminal window
$ mediastreamsegmenter -w 499 -t 1 224.0.0.50:9121 -s 16 -D -T -f ~/Desktop/hls_server/hls

システム内蔵カメラで音声・動画をキャプチャすることも、ローカル動画ファイルを指定することもできます。

Terminal window
$ ffmpeg -f avfoundation -list_devices true -i ""
[AVFoundation indev @ 0x7f924d904400] AVFoundation video devices:
[AVFoundation indev @ 0x7f924d904400] [0] FaceTime高清摄像头(内建)
[AVFoundation indev @ 0x7f924d904400] [1] Capture screen 0
[AVFoundation indev @ 0x7f924d904400] AVFoundation audio devices:
[AVFoundation indev @ 0x7f924d904400] [0] LarkAudioDevice
[AVFoundation indev @ 0x7f924d904400] [1] 外置麦克风
[AVFoundation indev @ 0x7f924d904400] [2] MacBook Pro麦克风
$ ffmpeg -f avfoundation -framerate 30 -pixel_format uyvy422 -i "0:" -c:v h264 -fflags nobuffer -tune zerolatency -f mpegts udp://192.168.1.5:9121

Terminal window
$ ffmpeg -re -i "/Users/tony/Downloads/sample.mp4" -c:v h264 -fflags nobuffer -tune zerolatency -f mpegts udp://192.168.1.5:9121

  1. seek が不正確な場合の解決方法は? mp4 は指定したタイムスタンプに seek できますが、ts はファイルの特定の positionseek するもので、指定した時点に直接 seek することはできません。 ffplay.cevent_loop 関数に seek に関するコードが含まれています。 ts の場合、具体的な seek 操作の関数呼び出し関係は avformat_seek_file()=> av_seek_frame() => seek_frame_internal() => seek_frame_byte() です。 mp4 の場合、具体的な seek 操作の関数呼び出し関係は avformat_seek_file()=> av_seek_frame() => seek_frame_internal() =>mov_read_seek() です。

tsseek ロジックは次のとおりです。ファイルの位置が与えられると、ファイルポインタをその位置に直接移動します。その後 read_packet() を呼び出して ts パケット(188バイト)を読み取る際、以前に seek 操作を行っているため、ファイルポインタが ts packet のヘッダー位置(ヘッダーは 0x47 byte で始まる)を指していない可能性が高く、その場合は mpegts_resync() を呼び出して再同期を行いヘッダーを見つけてから、完全な ts packet を再度読み取る必要があります。 mp4seek 操作ロジックは次のとおりです。seek 対象のタイムスタンプが与えられると、mp4 内の各パケットのインデックス情報に基づいて、そのタイムスタンプに対応するパケットを見つけます。以下の mp4 のファイル構成からわかるように、Sample Table を利用することで、任意のタイムスタンプに対応する video/audio データパケットを素早く見つけることができます。

結論

  • mp4 ファイルの場合、インデックステーブルがあるため、特定のタイムスタンプに対応するデータを素早く見つけることができ、seek 操作は高速に完了します。
  • ts ファイルにはタイムスタンプとデータパケット位置の対応関係がないため、プレイヤーが seek のタイムスタンプ ts_seek を与えられた場合、まずファイルのビットレートからおおよその位置 pos を推定し、その位置のデータパケットのタイムスタンプ ts_actual を取得します。ts_actual < ts_seek の場合はさらに後方のデータパケットを読み続ける必要があり、ts_actual > ts_seek の場合は前方のデータパケットを読み、ts_seek に対応するデータパケットが見つかるまで続けます。そのため ts ファイルの操作はより時間がかかる可能性があります。tsCBR ストリームの場合、ts_actualts_seek の差は一般に小さく、seek は比較的速いですが、tsVBR ストリームの場合、ts_actualts_seek が大きく異なる可能性があり、seek は比較的遅くなります。

HLS_seekHLS Seek

  1. 異なる解像度の ts/fMP4 ファイルの互換性問題 Android 端末で m3u8 動画を再生する際に、画面が乱れる問題が発生しました。原因は ts の解像度が変化したことでした。 この場合は必ず hevc_mp4toannexb を追加する必要があります。元のプロトコルは h264_mp4toannexb のみをサポートしています。 H.264/5 のビットストリームには Annex-BAVCC の2つの形式があります。 AVCC は長さ情報で NALU を分割し、mp4flv などのコンテナ形式で使用されます。 Annex-Bstart code(0x000001 または 0x00000001)NALU を分割し、mpegts ストリーミングメディアファイルで使用されます。 hevc_mp4toannexb を追加すると、すべてのフレームで動画の幅と高さを解析できるようになり、解像度切り替え時の画面乱れの問題が発生しなくなります。

参考資料

  1. https://developer.apple.com/documentation/http_live_streaming/understanding_the_http_live_streaming_architecture
  2. https://en.wikipedia.org/wiki/MPEG_transport_stream
  3. http://anddymao.com/2021/08/03/2021-08-03-%E4%B8%80%E7%A7%8D%E4%B8%87%E8%83%BDhls%E5%8D%8F%E8%AE%AE%E8%A7%A3%E6%9E%90%E6%96%B9%E6%B3%95/