Wowza Streaming Engine での HLS ストリーミング

## はじめに

この記事では、Wowza Streaming Engine での HLS 方式でのストリーミングに関する
技術的に詳細な設定・カスタマイズの方法について触れます。

## HLS プレイリスト (マニフェスト) について

HLS プレイリストには、`EXT-X-VERSION` タグと呼ばれる Apple HLS (HTTP Live Streaming) のプレイリスト互換性バージョンを示すタグが含まれています。

Wowza Streaming Engine の HTTPStreamer の既定の設定では、Apple HLS 互換性バージョン 3 のプレイリストを生成します。

```text
#EXT-X-VERSION:3
```

VOD またはライブアプリケーションの `Application.xml` (`/usr/local/WowzaStreamingEngine/conf/[アプリ名]/Application.xml`) 内の
以下のパラメーターで HLS プレイリストの互換性バージョンを制御することができます。

Wowza Streaming Engine では、バージョン 3 から 6 までをサポートしています。

| 項目 | 内容 |
| --- | --- |
| XML パス | /Root/Application/HTTPStreamer |
| プロパティ名 (Name) | cupertinoExtXVersion |
| プロパティのタイプ (Type) | Integer |
| プロパティの値 (Value) の説明 | プレイリストの互換性バージョンを指定する (既定値: 3) |

Wowza Streaming Engine では、指定された `EXT-X-VERSION` (プレイリストの互換性バージョン) に基づいてプレイリスト機能を有効または無効にすることができます。

次の機能は `EXT-X-VERSION` の値によって制御されます。

* **浮動小数点形式によるセグメント長**
  * `EXT-X-VERSION` が 3 以上の場合、整数形式ではなく浮動小数点形式を使用してセグメント長を表します
* **コーデック形式**
  * `EXT-X-VERSION` が 4 以上の場合、iOS 4.0 以降のコーデック形式 (例: avc1.42c015) を使用して、playlist.m3u8 レスポンスのコーデック値を表します
  * `EXT-X-VERSION` が 4 未満の場合、iOS 4.0 以前のコーデック形式 (例: avc1.66.21) を使用します
  * `cupertinoCodecStringFormatId` (パス名:/Root/Application/HTTPStreamer) プロパティの値によってコーデック形式の制御することも可能です
    * `Integer` 型で、値が 2 の場合、iOS 4.0 以降のコーデック形式を使用します
    * `Integer` 型で、値が 1 の場合、iOS 4.0 以前のコーデック形式を使用します

## HLS セグメントの長さについて

Wowza Streaming Engine では、HLS ストリーミングを行うためにビデオファイルをセグメントに分割してプレイヤーに提供します。

分割するセグメントの長さは、既定では 10 秒 (10000 ミリ秒) となっていますが、
以下のアプリケーション プロパティを変更することでセグメントの長さをカスタマイズすることができます。

> 注意
>
> HLS アダプティブストリーミングが正しく動作するには、ビデオセグメントの始まりは必ずキーフレーム (I-フレーム) で開始する必要があり、
> ビデオセグメントの境界は キーフレームの間隔と整合性がとれている必要があります。
> 例えば、10秒のビデオセグメントの場合、2秒、2.5秒、5秒、10秒などのキーフレーム間隔でエンコードされたビデオを入力する必要があります。
> これにより、再生中に異なるビットレートや解像度のビデオストリーム間で再生の切り替えを正しく行うことができます。
>
> このため、Wowza Streaming Engine に入力するビデオ (VOD ファイルやライブストリーム) は、指定するセグメントの長さに気を付けて入力する必要があります。

### VOD ストリーミングのセグメントの長さの設定パラメーター

VOD アプリケーションの `Application.xml` (`/usr/local/WowzaStreamingEngine/conf/[アプリ名]/Application.xml`) の
以下の項目を設定することで、HLS VOD ストリーミングのセグメントの長さを変更することができます。

| 項目 | 内容 |
| --- | --- |
| XML パス | /Root/Application/HTTPStreamer |
| プロパティ名 (Name) | cupertinoChunkDurationTarget |
| プロパティのタイプ (Type) | Integer |
| プロパティの値 (Value) の説明 | セグメントの長さ (ミリ秒) を指定する (既定値: 10000) |

### ライブストリーミングのセグメントの長さの設定パラメーター

ライブ入力デバイス等からのオーディオ・ビデオ パケットは、 Wowza Streaming Engine で時刻に基づいてセグメントに分割されます。
各セグメントの長さは、`cupertinoChunkDurationTarget` プロパティによって制御されます。
セグメントは、作成時にアクセス可能なセグメント リストに追加されます。
リストに格納される項目の最大数は、`cupertinoMaxChunkCount` プロパティによって制御されます。
MPEG-DASH クライアント (プレイヤー) がストリームを要求すると、Wowza Streaming Engine は最近追加された n 個のセグメントを含むマニフェストを提供します。
マニフェストで返されるアイテムの数 (n) は、`cupertinoPlaylistChunkCount` プロパティによって制御されます。

また、ライブストリーム リピーター システムは、オリジン/エッジの構成で単一のライブストリームを複数のエッジ サーバーに配信するために使用されます。
エッジ サーバーは、ライブストリームを最初に要求するときに、オリジンへセグメント化されたライブストリームのリクエストを行って、クライアントに配信します。
`cupertinoRepeaterChunkCount` プロパティは、最初の接続後すぐにオリジンからエッジに送信されるセグメントの数を制御します。
`cupertinoRepeaterChunkCount` は `cupertinoPlaylistChunkCount` 以上で `cupertinoMaxChunkCount` 未満であることが最適です。
この設定パラメーターは、**Live Edge** タイプのアプリケーションでリピーター構成となっている場合に利用します。

ライブアプリケーションの `Application.xml` (`/usr/local/WowzaStreamingEngine/conf/[アプリ名]/Application.xml`) の
以下の項目を設定することで、HLS ライブストリーミングのセグメントの長さを変更することができます。

| 項目 | 内容 |
| --- | --- |
| XML パス | /Root/Application/LiveStreamPacketizer |
| プロパティ名 (Name) | cupertinoChunkDurationTarget |
| プロパティのタイプ (Type) | Integer |
| プロパティの値 (Value) の説明 | セグメントの長さ (ミリ秒) を指定する (既定値: 10000) |

| 項目 | 内容 |
| --- | --- |
| XML パス | /Root/Application/LiveStreamPacketizer |
| プロパティ名 (Name) | cupertinoMaxChunkCount |
| プロパティのタイプ (Type) | Integer |
| プロパティの値 (Value) の説明 | WSE 内部で格納する有効なライブストリームのセグメント数を指定する (既定値: 10) |

| 項目 | 内容 |
| --- | --- |
| XML パス | /Root/Application/LiveStreamPacketizer |
| プロパティ名 (Name) | cupertinoPlaylistChunkCount |
| プロパティのタイプ (Type) | Integer |
| プロパティの値 (Value) の説明 | プレイリストで提供するライブストリームのセグメント数を指定する (既定値: 5) |

| 項目 | 内容 |
| --- | --- |
| XML パス | /Root/Application/LiveStreamPacketizer |
| プロパティ名 (Name) | cupertinoRepeaterChunkCount |
| プロパティのタイプ (Type) | Integer |
| プロパティの値 (Value) の説明 | エッジからオリジンへの最初の接続後、オリジンからエッジにすぐに送信されるセグメント数を指定する (既定値: 5) |

## HLS Audio-only ストリームの設定

過去の Apple デバイス向けの Apple HLS オーサリングガイドラインでは、
3G ネットワークなどの低帯域ネットワークに向けたアクセスのために、
HLS ストリーミング コンテンツに Audio-only (音声のみ) のストリームを用意することが
ガイドラインとして設けられていました。

例えば、取得したプレイリスト
(例: [https://[アドレス]/[アプリ名]/mp4:sample.mp4/playlist.m3u8](https://[アドレス]/[アプリ名]/mp4:sample.mp4/playlist.m3u8))
は以下のような内容となります。

`_ao.m3u8` のサフィックスが付いたプレイリスト (以下の例では `chunklist_[WowzaセッションID]_ao.m3u8`) が、
Audio-only ストリームのプレイリストです。

```text
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-STREAM-INF:BANDWIDTH=868638,CODECS="avc1.42c015,mp4a.40.2",RESOLUTION=512x288
chunklist_w298755728.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=116046,CODECS="mp4a.40.2"
chunklist_w298755728_ao.m3u8
```

> 現在のガイドラインには、該当する記載はなくなっているようです。
>
> [HTTP Live Streaming (HLS) Authoring Specification for Apple Devices](https://developer.apple.com/documentation/http_live_streaming/http_live_streaming_hls_authoring_specification_for_apple_devices)

この Audio-only のストリームが追加されるように HLS プレイリストの変更を行うには、以下のプロパティの設定を行います。

### VOD HLS Audio-only ストリームの設定

VOD アプリケーションの `Application.xml` (`/usr/local/WowzaStreamingEngine/conf/[アプリ名]/Application.xml`) の
以下の項目を設定することで、HLS VOD ストリーミングのプレイリストに Audio-only ストリームを追加します。

| 項目 | 内容 |
| --- | --- |
| XML パス | /Root/Application/HTTPStreamer |
| プロパティ名 (Name) | cupertinoAutoCreateMultibitratePlaylist |
| プロパティのタイプ (Type) | Boolean |
| プロパティの値 (Value) の説明 | true に設定する (既定値: false) |

### ライブ HLS Audio-only ストリームの設定

ライブアプリケーションの `Application.xml` (`/usr/local/WowzaStreamingEngine/conf/[アプリ名]/Application.xml`) の
以下の項目を設定することで、HLS ライブストリーミングのプレイリストに Audio-only ストリームを追加します。

| 項目 | 内容 |
| --- | --- |
| XML パス | /Root/Application/LiveStreamPacketizer |
| プロパティ名 (Name) | cupertinoCreateAudioOnlyRendition |
| プロパティのタイプ (Type) | Boolean |
| プロパティの値 (Value) の説明 | true に設定する (既定値: false) |

| 項目 | 内容 |
| --- | --- |
| XML パス | /Root/Application/HTTPStreamer |
| プロパティ名 (Name) | cupertinoAutoCreateMultibitratePlaylist |
| プロパティのタイプ (Type) | Boolean |
| プロパティの値 (Value) の説明 | true に設定する (既定値: false) |

## HLS KeyFrames-only プレイリストの設定

Apple のネイティブ HLS プレイヤーでは、VOD コンテンツのトリックプレイ再生をサポートしています。
トリックプレイ再生とは、プレーヤーでコンテンツの巻き戻しや早送りをしてコンテンツのタイムラインを探すときに、
ビューア―に視覚的な手がかりとなるビデオのサムネイルを提供するものです。

トリックプレイ再生をサポートするために特別な目的のコンテンツを別に作成する必要はなく、
ビデオストリームのキーフレーム[^1] の場所をプレイヤーに提供するだけです。
ビデオストリームのキーフレームの場所を指定するために、Apple iOS 5 以降では KeyFrames-only プレイリスト (Iフレームのみのプレイリスト) を使用します。

> この設定はラVODアプリケーションにのみ有効な設定です

Wowza Streaming Engine では、KeyFrames-only プレイリストを動的に生成し、ビデオストリームのキーフレームをストリーミングすることができます。
KeyFrames-only プレイリストは、`playlist.m3u8` プレイリストの中で `EXT-X-I-FRAME-STREAM-INF` タグを使って URL を指定します。
KeyFrames-only プレイリストは `EXT-X-I-FRAMES-ONLY` タグを使用してキーフレームのみを提供するプレイリストです。
KeyFrames-only プレイリストでは、`EXTINF` タグはセグメントの長さのかわりにキーフレームの間隔を参照します。

[^1]: キーフレームは、I フレーム、または、イントラ コード化されたフレームと呼ばれることもあり、
ビデオフレームのエンコード時に他のフレームから独立してエンコードされたビデオ フレームです。

この I-Frames-only のプレイリストが追加されるように HLS プレイリストの変更を行うには、以下のプロパティの設定を行います。

VOD アプリケーションの `Application.xml` (`/usr/local/WowzaStreamingEngine/conf/[アプリ名]/Application.xml`) の
以下の項目を設定することで、HLS VOD ストリーミングのプレイリストに I-Frames-only プレイリストを追加します。

| 項目 | 内容 |
| --- | --- |
| XML パス | /Root/Application/HTTPStreamer |
| プロパティ名 (Name) | cupertinoExtXVersion |
| プロパティのタイプ (Type) | Integer |
| プロパティの値 (Value) の説明 | 4 以上の値に設定する (既定値: 3) |

| 項目 | 内容 |
| --- | --- |
| XML パス | /Root/Application/HTTPStreamer |
| プロパティ名 (Name) | cupertinoCreateKeyFrameOnlyPlaylist |
| プロパティのタイプ (Type) | Boolean |
| プロパティの値 (Value) の説明 | true に設定する (既定値: false) |

プレイリストのサンプルは以下の通りです。

* playlist.m3u8

```text
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-STREAM-INF:BANDWIDTH=868638,CODECS="avc1.42c015,mp4a.40.2",RESOLUTION=512x288
chunklist_w1520434929.m3u8
#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=875,CODECS="avc1.42c015",URI="chunklist_w1520434929_ko.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=116046,CODECS="mp4a.40.2"
chunklist_w1520434929_ao.m3u8
```

* KeyFrames-only プレイリスト

```text
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-TARGETDURATION:2
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-I-FRAMES-ONLY
#EXTINF:2.0,
#EXT-X-BYTERANGE:999624@376
media_w1520434929_ko_0.ts
#EXTINF:2.0,
#EXT-X-BYTERANGE:999624@376
media_w1520434929_ko_1.ts
#EXTINF:2.0,
#EXT-X-BYTERANGE:999624@376
media_w1520434929_ko_2.ts
#EXTINF:2.0,
#EXT-X-BYTERANGE:999624@376
media_w1520434929_ko_3.ts
  :
```

## HLS Audioストリームの TS パッケージングの設定

Wowza Streaming Engine の既定の設定では、HLS Audio ストリームは、MPEG-2 エレメンタリストリームでパッケージングされます。

以下のプロパティの設定を行うことで、HLS Audio ストリームをビデオストリームと同様に
HLS Audio ストリームを　MPEG-2 トランスポートストリーム (TS) でパッケージングを行います。

### VOD HLS Audio ストリームの TS パッケージングの設定

VOD アプリケーションの `Application.xml` (`/usr/local/WowzaStreamingEngine/conf/[アプリ名]/Application.xml`) の
以下の項目を設定することで、HLS VOD ストリーミングのプレイリストに Audio-only ストリームを追加します。

| 項目 | 内容 |
| --- | --- |
| XML パス | /Root/Application/HTTPStreamer |
| プロパティ名 (Name) | cupertinoPacketizeAllStreamsAsTS |
| プロパティのタイプ (Type) | Boolean |
| プロパティの値 (Value) の説明 | true に設定する (既定値: false) |

### ライブ HLS Audio ストリームの TS パッケージングの設定

ライブアプリケーションの `Application.xml` (`/usr/local/WowzaStreamingEngine/conf/[アプリ名]/Application.xml`) の
以下の項目を設定することで、HLS ライブストリーミングのプレイリストに Audio-only ストリームを追加します。

| 項目 | 内容 |
| --- | --- |
| XML パス | /Root/Application/LiveStreamPacketizer |
| プロパティ名 (Name) | cupertinoPacketizeAllStreamsAsTS |
| プロパティのタイプ (Type) | Boolean |
| プロパティの値 (Value) の説明 | true に設定する (既定値: false) |

## タイムコードに基づいたライブストリームのセグメントの番号付けの設定

Wowza Streaming Engine では、エンコーダーから受信したライブストリームにタイムコードが含まれている場合に、
タイムコードに基づいたセグメント (チャンク) の番号付けを行うことができます。

> この設定はライブアプリケーションにのみ有効な設定です

この機能を有効にするには、ライブアプリケーションの `Application.xml` (`/usr/local/WowzaStreamingEngine/conf/[アプリ名]/Application.xml`) の
以下のプロパティを設定します。

| 項目 | 内容 |
| --- | --- |
| XML パス | /Root/Application/LiveStreamPacketizer |
| プロパティ名 (Name) | cupertinoCalculateChunkIDBasedOnTimecode |
| プロパティのタイプ (Type) | Boolean |
| プロパティの値 (Value) の説明 | true に設定する (既定値: false) |

この機能を有効にすると、セグメントの ID はタイムコードを cupertinoChunkDurationTarget 値で割った (割り算の) 商に等しくなります。

> 注意: `cupertinoCalculateChunkIDBasedOnTimecode` プロパティは、
> 時刻同期されたタイムコードを Wowza Streaming Engine に送信するエンコーダーを使う場合のみ有効にしてください。
> 時刻同期されたタイムコードは、UTC またはその他の時刻をベースに同期するようにします。
>
> もし、時刻同期されたタイムコードを送信しないエンコーダーのライブソースストリームと `cupertinoCalculateChunkIDBasedOnTimecode` が使用されている場合、
> ソースストリームが再起動すると セグメント ID は 0 で再起動するか、場合によってはランダムな値で再起動します。
> HTTP オリジンを使ってプライマリ サーバーとバックアップ サーバーの2つのソースから取り込まれたライブ ストリームを取り扱う場合、
> セグメント ID の整合性がとれなくなってしまうため、特に問題になります。