ABRアルゴリズムを混乱させないトランスコーディングラダーの設計方法
HLSの再生を実際の環境で観察したことがある方なら、一度は見たことがあるでしょう。ストリームが2つのレンディション間を行ったり来たりする現象です。上がって、下がって、上がって、下がって。視聴者には数秒ごとに画質が変化し続けるように見えます。これは低いレンディションのままでいるよりも悪い体験です。安定した720pのストリームは意図的なものに感じますが、720pと1080pの間を10秒ごとに切り替わるストリームは、壊れているように感じます。
根本的な原因はほぼ常に同じです。エンコーディングラダーのレンディション間のビットレートが近すぎるか、段間の画質差が帯域幅の増加に見合っていないかです。クライアント側のABRアルゴリズムが判断を下せないのは、「これなら大丈夫」と「これは無理」の差がきわめて小さいからです。
これを適切に修正する方法について話しましょう。
ビット毎ピクセル(BPP)による健全性チェック
何よりもまず、ビット毎ピクセル(BPP)がラダーについて何を示しているかを理解する必要があります。これは、指定された解像度に対して特定のビットレートが適切かどうかを評価する最もシンプルな指標です。
計算式は簡単です:
BPP = bitrate / (width × height × framerate)
例えば、1920×1080のストリームを4500 kbps、30 fpsで配信する場合:
BPP = 4,500,000 / (1920 × 1080 × 30) = 0.072
なぜこれが重要なのでしょうか?BPPは各段の圧縮密度を示すからです。ラダーの隣接する2つの段のBPP値が非常に近い場合、視聴者は意味のある画質の違いを感じません。しかし、ABRアルゴリズムはそれでも切り替えようとします。それがピンポン現象の原因です。
適切に設計されたラダーは、解像度が上がるにつれてBPPカーブが下降するはずです。これはビデオコーデックの実際の特性を反映しています。高解像度では、480pと同じ知覚品質を達成するためにピクセルあたりのビット数が少なくて済みます。BPPがラダー全体で平坦または不規則な場合、何かがおかしいです。
ここで参考になるのが「0.70の法則」です。ピクセル数を倍にする場合(例えば720pから1080pへ)、低い解像度のBPPの約0.70倍を適用するという考え方です。これは法則ではなくヒューリスティックですが、異常値を素早く発見する方法を提供します。ラダーのBPP値をプロットして、ある段が隣接する段と比べて明らかに高すぎたり低すぎたりする場合、その段は問題を引き起こします。
要点:見栄えの良い丸い数字のビットレートを選ぶだけではいけません。各段のBPPを計算し、カーブが合理的であることを確認してください。隣接する2つの段のBPPが15〜20%以内の差であれば、視聴者には区別がつきませんが、ABRヒューリスティックは切り替えに時間を浪費します。
ビットレートの間隔:1.5倍ルールの目安
普遍的な標準はありませんが、一般的なエンジニアリングガイドラインとして、隣接するビットレートの段の間に少なくとも1.5倍の比率を維持することが推奨されています。一部の実装ではこれを2倍にしています。
なぜでしょうか?ABRアルゴリズムは帯域幅推定(BWE)を使ってどのレンディションを選ぶかを決定するからです。推定には信頼区間があり、正確ではありません。2つのレンディションが2.5 Mbpsと3.0 Mbpsの場合、やや不安定な接続では、BWEが3.0 Mbpsの上下を容易に振動し、常に切り替えが発生します。代わりに2.0 Mbpsから4.0 Mbpsへのジャンプであれば、アルゴリズムが切り替えをトリガーするにはかなり大きな帯域幅の変化が必要です。結果として、より安定した再生が得られます。
具体的な例を示しましょう。4段のクリーンなラダーがあるとします:
| 解像度 | ビットレート | BPP (30fps) | 前段との比率 |
|---|---|---|---|
| 480×270 | 400 kbps | 0.103 | — |
| 960×540 | 2000 kbps | 0.129 | 5.0× |
| 1280×720 | 2800 kbps | 0.101 | 1.4× |
| 1920×1080 | 4500 kbps | 0.072 | 1.6× |
一見すると妥当に見えます — 4つの解像度、増加するビットレート。しかし540pから720pへのジャンプを見てください:2000 kbpsから2800 kbps。これはわずか1.4倍の比率です。2.5〜3 Mbps付近を推移する接続(ほとんどのモバイル接続がそうです)では、BWEが常にその閾値を越えたり下回ったりします。上がって、下がって、上がって、下がって。視聴者は数セグメントごとに解像度が切り替わるのを目にします。
もう一つの問題もあります。BPPは実際に540pの0.129から720pの0.101に低下しています。つまり、視聴者はより多くのピクセルを得ますが、ピクセルあたりのデータ量は少なくなります。コンテンツによっては、720pのレンディションが540pと比べて意味のある画質向上に見えない場合があります — 解像度は追加したものの、圧縮の余裕を失っています。ABRアルゴリズムは無駄な切り替えを行っていることになります。
このラダーのより良いバージョンは、720pのビットレートを引き上げ、540pを引き下げることです:
| 解像度 | ビットレート | BPP (30fps) | 前段との比率 |
|---|---|---|---|
| 480×270 | 400 kbps | 0.103 | — |
| 960×540 | 1500 kbps | 0.096 | 3.75× |
| 1280×720 | 3000 kbps | 0.109 | 2.0× |
| 1920×1080 | 5800 kbps | 0.093 | 1.93× |
これで540pから720pへのジャンプはきれいな2倍の比率になりました。プレーヤーが切り替えを検討するには、BWEが倍になる必要があります。そしてBPPは実際に0.096から0.109に増加しています。つまり720pの段はより多くのピクセルとより良い圧縮品質を提供し、視聴者は本当の改善を感じます。720pから1080pへのジャンプも1.93倍と同様に堅実で、BPPは0.093にわずかに低下するだけです。これは高解像度での期待される効率向上を反映しています。
レートごとの確認:単一レンディション再生テスト
チームが実施しているのを滅多に見ないが、非常に重要なことがあります:各レンディションを個別に再生し、全体を視聴することです。
当たり前のことのように聞こえますが、ほとんどの人は完全なマルチバリアントストリームとしてのみABRをテストします。単一のレンディションを分離してエンドツーエンドで再生することはありません。これを行うと、ABRの動作が隠してしまう問題を発見できます:
- 宣言されたビットレートでもバッファリングが発生するレンディション(プレイリストで宣言されたBANDWIDTHが実際のピークビットレートに比べて低すぎるため)
- エンコーダーが特定のシーンで苦戦し、目に見えるアーティファクトが発生しているレンディション
- 解像度とビットレートの組み合わせがターゲットデバイスのデコーダーにとって負荷が高すぎるため、フレームレートが低下またはスタッターが発生するレンディション
これをテストするには、いくつかの方法で単一レンディション再生を強制できます:
hls.jsデモページを使用する場合:マルチバリアントストリームをロードし、品質セレクターのドロップダウンで各レベルを一つずつ手動で固定します。hlsjs.video-dev.org/demo/のhls.jsデモは、すべての品質レベルを表示し、ABRをオーバーライドできます。代表的なコンテンツを少なくとも数分間再生してください。「Buffer & Statistics」タブでドロップフレームを確認してください。
AppleプラットフォームでAVPlayerを使用する場合:AVPlayerItemのpreferredPeakBitRateとpreferredMaximumResolutionを使って、再生を単一のレンディションに制限します。さらに簡単な方法として、1つのバリアントのみを含むテストプレイリストを作成できます。
ffprobeまたはmediainfoを使用する場合:何かを再生する前に、各レンディションの実際のビットレート統計を確認します。マスタープレイリストのBANDWIDTH値は平均だけでなく、ピークを考慮する必要があります。VBRエンコーディングのスパイクが平均の40%以上ある場合、宣言するBANDWIDTHにはそれを反映させる必要があります。
単一のレンディションが宣言されたビットレートでスムーズに再生できない場合、ABRモードでは確実に問題を引き起こします。ABRアルゴリズムは十分な帯域幅があると考えてそのレンディションを選択し、VBRのスパイクに遭遇してストールし、下位に戻り、回復して再びそのレンディションを選択します — ピンポンの完成です。
セグメント長:ABRスイッチングクロック
見落とされがちなもう一つの要因があります。セグメント長はABRアルゴリズムが判断を下す頻度を直接制御します。各セグメント境界は潜在的な切り替えポイントです。つまり、2秒のセグメントを使用すると、プレーヤーは毎分最大30回再評価して切り替えることができます。6秒のセグメントでは、毎分10回に減少します。10秒のセグメントでは、わずか6回です。
ラダーのビットレート間隔がすでに狭い場合、これは非常に重要です。短いセグメントと近いビットレートの段の組み合わせは最悪です — ABRアルゴリズムに、視聴者が見る必要のない微小な切り替えを行う最大の機会を与えているのです。
逆に、長いセグメントは振動に対する自然なダンパーとして機能します。帯域幅推定が変動しても、プレーヤーは取得したセグメントの期間中、現在のレンディションにコミットしなければなりません。次の判断ポイントが来るまでに、BWEが安定している場合もあります。
HLS仕様では特定の長さを義務付けていませんが、Appleのオーサリングガイドラインでは6秒のターゲットを推奨しています。実際には:
- 2秒のセグメントは、高速起動と素早い適応が重要な低遅延ライブに適しています。ただし、常に切り替わるのを避けるため、十分な間隔のラダーが必要です。
- 6秒のセグメントは、VODと標準的なライブにとって良いデフォルトです。判断間にABRアルゴリズムが信頼性の高い帯域幅推定を構築するのに十分な時間を与えます。
- 10秒のセグメントは非常に安定していますが、適応が遅くなります。帯域幅が急激に低下した場合、プレーヤーは時間内に完了できない高ビットレートのセグメントのダウンロードに固執します。
VBRエンコーディングにも微妙な点があります。セグメント内のビットレートの変動はセグメント長とともに増加します。シーン転換の10秒セグメント — 静的なショットからアクションシーケンスへ — は内部的に巨大なビットレート変動を持つ可能性があります。プレイリストで宣言されたBANDWIDTHが全体の平均に一致してもセグメントごとのピークに一致しない場合、ABRアルゴリズムは予想外の事態に直面します。短いセグメントはセグメントごとのビットレートがより一貫する傾向があり、BWEの精度が向上します。
結論:振動が見られ、ラダーの間隔が適切に見える場合は、セグメント長を確認してください。4秒から6秒に変更するだけで十分な場合があります。
Network Link Conditionerで実際の条件をシミュレーションする
安定した100 Mbpsの光回線でABRをテストしても意味がありません。実際の環境をシミュレーションする必要があり、macOSではAppleのNetwork Link Conditionerが最適なツールです。
AppleのAdditional Tools for Xcodeパッケージから入手できます。XcodeでXcode > Open Developer Tool > More Developer Toolsに移動すると、Apple開発者ダウンロードページに遷移します。「Additional Tools for Xcode」を検索し、お使いのXcodeバージョン用のDMGをダウンロードし、開いてHardwareフォルダ内のNetwork Link Conditioner.prefPaneを見つけます。ダブルクリックしてインストールすると、システム設定(古いmacOSではシステム環境設定)にペインとして表示されます。特定のスループット、レイテンシ、パケットロス率、DNSの遅延を持つ帯域幅プロファイルを定義できます。
重要なカスタムプロファイルを作成しましょう:
- 中程度の4G:下り8 Mbps / 上り2 Mbps、80ms RTT、1%パケットロス
- 悪いWiFi:下り3 Mbps / 上り1 Mbps、150ms RTT、3%パケットロス
- 遷移テスト:15 Mbpsで開始し、再生中に手動で2 Mbpsに切り替え
最後のテストが決定的なものです。ラダーが適切に設計されていれば、プレーヤーは数秒以内にスムーズに低いレンディションに移行し、そこに留まるはずです。2つのレンディション間で振動を始めたら、帯域幅境界で段が近すぎるということです。
iOSデバイスでは、Network Link ConditionerはDeveloper設定から利用できます(デバイスをXcodeに接続した後、設定 > デベロッパーで有効にします)。
これらのテストの目標は単に「バッファリングするか?」ではなく、「ストリームはレンディションに落ち着き、そこに留まるか?」です。良いABR体験とは、切り替えがまれで決定的なものです。視聴者は一度だけ画質の変化を見て、その後安定します。
AppleのAVMetricsで本番環境の切り替えを監視する
iOS 18以降、AppleはAVFoundationにAVMetrics APIを導入しました。これはフィールドでのABR動作を監視するための画期的なツールです。
目的のために重要なイベントタイプはバリアント切り替えイベントです。AVPlayerがHLSバリアント間を切り替えるたびに、切り替え元、切り替え先、メディアレンディションの詳細を知らせるメトリックイベントを取得できます。プレーヤーが再バッファリングする際のストールイベントと、セッション終了時の全体的なKPIを含むサマリーイベントも取得できます。
Swiftのパターンは以下の通りです:
let playerItem: AVPlayerItem = // your configured item
let switchMetrics = playerItem.metrics(
forType: AVMetricPlayerItemVariantSwitchEvent.self
)
let stallMetrics = playerItem.metrics(
forType: AVMetricPlayerItemStallEvent.self
)
for await (event, _) in switchMetrics.chronologicalMerge(with: stallMetrics) {
switch event {
case let switchEvent as AVMetricPlayerItemVariantSwitchEvent:
// Log: from variant, to variant, timestamp
await analytics.logSwitch(switchEvent)
case let stallEvent as AVMetricPlayerItemStallEvent:
// Log: stall duration, variant at time of stall
await analytics.logStall(stallEvent)
default:
break
}
}
分析データで注目すべき点:
- 切り替え頻度:平均セッションで毎分3〜4回以上の切り替えがある場合、ラダーに問題があります。健全なストリームでは、通常起動時に1〜2回切り替わる程度です。
- 振動パターン:2つのレンディションが交互に切り替わり続ける — これは段が近すぎる典型的な兆候です。
- アップスイッチに相関するストール:高いレンディションに切り替えた直後にストールが発生する場合、プレイリストのBANDWIDTH宣言が低すぎます。
WWDC 2025では、Appleがバリアント切り替えイベントにメディアレンディション情報を含めるようにAVMetricsを拡張し、切り替え中にどのオーディオ/ビデオ/字幕トラックがアクティブだったかをより簡単に確認できるようになりました。
Appleプラットフォーム以外の場合、hls.jsのLEVEL_SWITCHEDおよびFRAG_BUFFEREDイベントから同様のデータを収集できます。同じ原則が適用されます。
hls.jsで実験する:ABR動作のチューニング
hls.jsデモページ(hlsjs.video-dev.org/demo/)は、WebでのABR切り替え動作を実験するための最高の無料ツールです。HLSストリームをロードし、「Real-time metrics」と「Buffer & Statistics」パネルを使って何が起こるかを観察してください。
実験すべき主要なhls.jsの設定パラメータ:
abrEwmaFastVoDとabrEwmaSlowVoD:これらは帯域幅推定のための指数加重移動平均(EWMA)を制御します。低い値はプレーヤーが帯域幅の変化に速く反応します(より積極的な切り替え)。高い値はより保守的になります(切り替えが遅く、より安定)。切り替えが多すぎる場合は、これらの値を増やしてみてください。abrBandWidthFactor(デフォルト:0.95)とabrBandWidthUpFactor(デフォルト:0.7):これらは安全マージンです。プレーヤーはビットレートがestimatedBandwidth × factorを下回るレンディションを選択します。アップスイッチファクターは意図的に低く設定されています — プレーヤーはダウンスイッチよりアップスイッチに対してより保守的です。ラダーの間隔が狭い場合、振動を減らすためにabrBandWidthUpFactorを0.6に下げることを検討してください。abrMaxWithRealBitrate(デフォルト:false):有効にすると、ABRコントローラーはプレイリストで宣言されたBANDWIDTHではなく、取得したセグメントの実測ビットレートを使用します。宣言されたビットレートが不正確な場合に特に有用です。
しかし、ここで重要なことがあります:安定した再生を得るためにこれらのパラメータを大幅にチューニングする必要がある場合、おそらくラダーが間違っています。これらのパラメータは微調整用です。エンコーディングラダー自体が基盤です。適切な間隔のラダーは、どのプレーヤーでもデフォルトのABR設定でうまく動作します。
実践的な推奨事項
チェックリストにまとめるなら:
- ラダーの各段のBPPを計算する。解像度が上がるにつれてBPPが減少することを確認してください。BPPが隣接する段の15%以内にある段は削除または調整してください。
- 隣接する段の間で少なくとも1.5倍のビットレート比率を維持する。可能であれば2倍を推奨します。特に帯域幅の変動が最も大きな影響を与えるラダーの下半分では重要です。
- 各レンディションを個別にテストする。単一バリアント再生を強制し、代表的なコンテンツをエンドツーエンドで視聴してください。単独でスムーズに再生できなければ、ABRでもスムーズに再生できません。
- Network Link Conditionerを使用して帯域幅の低下をシミュレーションしてください。ストリームは素早くレンディションに落ち着き、そこに留まるべきです。
- セグメント長を確認する。2〜4秒で振動が見られる場合は、6秒を試してください。長いセグメントは判断間のBWEの安定化時間を増やすことで、自然に切り替え頻度を減少させます。
- プレーヤーを計測する。AppleではAVMetrics、Webではhls.jsイベントを使用してください。セッションごとの切り替え頻度を追跡してください。起動フェーズ以外でセッションの平均切り替え回数が数回以上ある場合は、調査してください。
- 宣言されたBANDWIDTHだけを信用しない。hls.jsの
abrMaxWithRealBitrateを使用するか、ffprobeでVBRのピークが宣言値を超えていないことを確認してください。 - 少ない段数の方が良い場合が多い。適切な間隔の5段ラダーは、半分の段が近すぎる10段ラダーより優れています。視聴者に12の画質レベルは必要ありません。意味のある違いがあり、確実に再生される4〜5段が必要です。
ABRの要点は、それが見えないことです。視聴者はABRが動作していることに気づくべきではありません。気づいた場合、何かが間違っています — そして10回中9回、原因はラダーです。
参考文献: