このページの目次
ストリーミングプロトコル
HLSは動画をtsセグメントに分割しHTTPで配信します(シンプルでCDNフレンドリー)。DASHはそのコーデック非依存版です。WebRTCは別の道——低遅延、P2P、インタラクティブなシーンに適しています。3つのプロトコルは、遅延とスケーラビリティの間で異なるトレードオフを行います。
概要
ストリーミングの本質は、遅延 vs スケールのトレードオフです。一端にはVOD(ビデオオンデマンド)や大規模ライブ配信があり、メディアを2〜10秒のセグメントに分割し、通常のHTTPで配信してCDNのキャッシュを活用し、千万単位の視聴者に届けます。その代償として、数秒から数十秒の遅延が生じます。もう一端にはリアルタイムインタラクション(ビデオ会議、クラウドゲーミング)があり、RTP/UDPを使用してフレームを直接プッシュし、遅延を数十ミリ秒に抑えますが、各接続はステートフルであり、CDNで分散するのが困難です。
このスペクトラム上で各プロトコルの位置を理解することが、フィールドの値を暗記するよりも重要です。
| 遅延 | プロトコル | 典型的なユースケース | 配信方式 |
|---|---|---|---|
| 20-40ms | Moonlight / WebRTC (LAN) | クラウドゲーミング / リモートデスクトップ | P2P / 専用線 |
| <500ms | WebRTC | ビデオ会議 / インタラクティブライブ配信 | SFU(ステートフル) |
| 0.5-2s | SRT / LL-HLS / LL-DASH | スポーツの低遅延ライブ配信 / 送信 | エッジ + HTTP |
| 3-10s | HLS / DASH(最適化後) | 通常のライブ配信 | CDN(HTTPキャッシュ) |
| 10-30s | HLS / DASH(デフォルト) | VOD / 大規模ライブ配信 | CDN(HTTPキャッシュ) |
なぜHTTPベースのセグメント化プロトコル(HLS/DASH)が、大規模ライブ配信とVODの主流になったのでしょうか?それは、「ストリーム」を「キャッシュ可能な小さなファイルの列」に退化させたからです。CDNはビデオを理解する必要がなく、通常のHTTPキャッシュが機能します。ファイアウォールやNATを透過するコストはゼロ(GETリクエストのみ)です。クライアントのロジックも単純です。その代償は遅延です。遅延は基本的に セグメントの長さ × プレイヤーのバッファリングセグメント数 に等しくなります。これが、後のLL-HLS/LL-DASHが解決しようとする核心的な矛盾です。
アダプティブビットレート (ABR) — セグメントストリーミングの心臓
セグメントが存在する理由は、「ダウンロードの利便性」のためではなく、セグメントの境界でシームレスに画質を切り替えるためです。サーバーは同一コンテンツに対して「エンコーディングラダー」をエンコードし、各ストリームを時間的に同期させたセグメントに分割します。クライアントは1〜2セグメントダウンロードするたびにネットワークを再評価し、次のセグメントのビットレートを決定します。
flowchart LR
subgraph ladder["ビットレートラダー — セグメント時間同期"]
A["1080p @ 5 Mbps"]
B["720p @ 2.8 Mbps"]
C["480p @ 1.4 Mbps"]
D["360p @ 0.8 Mbps"]
end
P["🎬 <b>プレイヤー ABR</b><br><small>1〜2セグメントごとにネットワークを再評価</small>"] ==>|"帯域が十分でバッファが深い"| A
P -.->|"ネットワークが悪化 → <br>セグメント境界で降格"| C
classDef player fill:#4493f826,stroke:#4493f8,stroke-width:2.5px
classDef hi fill:#3fb9501f,stroke:#3fb950,stroke-width:2px
classDef lo fill:#d299221f,stroke:#d29922,stroke-width:2px
classDef rung fill:#64748b14,stroke:#64748b
class P player
class A hi
class C lo
class B,D rung
すべてのラダーのセグメントNは同一の時間区間 [t, t+6s) をカバーしており、デコーダーがシームレスに接続できるように、切り替えは境界でのみ発生します。
ABRの判断には2つの主要なアプローチがあります。
- スループットベース(throughput-based):直近のセグメントのダウンロード速度を使用して帯域幅を推定し、推定帯域幅に安全係数を掛けた値を下回るビットレートのセグメントを選択します。問題は、セグメントのダウンロードがオンオフモードであることです。セグメントのダウンロードが完了するとアイドル状態になるため、単純な速度測定は帯域幅を体系的に過小評価する傾向があります。
- バッファベース(buffer-based、BOLAなど):「どのビットレートを選択するか」をバッファ水位の関数としてモデル化します。バッファが深ければ高ビットレートに挑戦し、バッファが浅ければバッファアンダーランを防ぐために保守的に降格します。
本番環境での実装(dash.js / hls.js)はこれらを組み合わせたものが多く、起動時の特殊処理(低ビットレートで素早く再生開始)も含まれます。ABRはストリーミング体験を真に決定する要因です。バッファリング、画質の急変、起動の遅れは、ほとんどがABR戦略の問題であり、プロトコル自体の問題ではありません。
HLS
Appleが2009年に発表し、RFC 8216で標準化されました。プレーンテキストの .m3u8 プレイリストとメディアセグメント(初期はMPEG-TS .ts、現代ではfMP4/CMAFが主流)を使用します。2層のリスト構造を持ちます。
マスタープレイリスト — 各バリアントのみを列挙:
#EXTM3U
#EXT-X-STREAM-INF:BANDWIDTH=5000000,CODECS="avc1.640028,mp4a.40.2",RESOLUTION=1920x1080
high.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2000000,CODECS="avc1.640028,mp4a.40.2",RESOLUTION=1280x720
medium.m3u8
メディアプレイリスト — 特定ビットレートのセグメントリスト:
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-TARGETDURATION:6 ← セグメントの最大長(整数化)
#EXT-X-MEDIA-SEQUENCE:0 ← 最初のセグメントのシーケンス番号(ライブでは増加)
#EXT-X-PLAYLIST-TYPE:VOD ← VOD/EVENT。ライブの場合は省略
#EXTINF:6.000,
segment-000.ts
#EXTINF:6.000,
segment-001.ts
#EXT-X-ENDLIST ← VOD専用: ストリームの終了を示す
再生フロー:マスターを取得 → 帯域幅/解像度に基づいてバリアントを選択 → メディアプレイリストを取得 → セグメントを順次フェッチ → 1〜2セグメントごとに帯域幅を再評価し、必要に応じて切り替え。
VODとLIVEの違いは、プレイリストの更新方法にあります。
- VOD:プレイリストを一度にすべて提供し、
EXT-X-ENDLISTを含みます。クライアントは自由にシークできます。 - EVENT:セグメントを末尾にのみ追加します(コンサートの完全な履歴など、視聴可能な履歴全体)。
- LIVE:スライディングウィンドウ——新しいセグメントが追加され、古いセグメントが削除されます。
ENDLISTはありません。クライアントは定期的に(約 target duration ごと)プレイリストを再フェッチして、新しいセグメントを取得する必要があります。この「プレイリストのポーリング」が、HLSの遅延が高くなる主な原因の一つです。
暗号化:#EXT-X-KEY:METHOD=AES-128,URI="key.bin",IV=0x...。セグメントはAES-128-CBCで暗号化されます。SAMPLE-AES はFairPlay/Widevineと組み合わせてDRMを実装します。
LL-HLS(低遅延HLS)
2つのアクションにより、遅延を10〜30秒から1〜2秒に圧縮します。セグメントをさらにパーシャルセグメント(約200〜500ms)に分割し、エンコードしながら公開します。ブロッキングプレイリストリロードにより、ポーリング遅延を解消します。クライアントは playlist?_HLS_msn=5&_HLS_part=2 をリクエストし、サーバーはリクエストを保持し、part 5.2 が実際に生成されてから応答を返します。これにより、ポーリングのアイドル状態がなくなります。
#EXT-X-SERVER-CONTROL:CAN-BLOCK-RELOAD=YES,PART-HOLD-BACK=1.0
#EXT-X-PART-INF:PART-TARGET=0.33
...
#EXT-X-PART:DURATION=0.33,URI="seg5.0.ts"
#EXT-X-PART:DURATION=0.33,URI="seg5.1.ts"
#EXT-X-PRELOAD-HINT:TYPE=PART,URI="seg5.2.ts" ← 次のpartを通知。クライアントは事前にリクエスト可能
MPEG-DASH
ISO/IEC 23009-1。ベンダーやコーデックに依存しません(HLSは歴史的にAppleエコシステムに縛られていましたが、DASHは当初からコーデック非依存でした)。リストはXML形式の MPD (Media Presentation Description) です。
<MPD type="dynamic" minBufferTime="PT1.5S" ← dynamic=ライブ, static=VOD
profiles="urn:mpeg:dash:profile:isoff-live:2011">
<Period>
<AdaptationSet mimeType="video/mp4" codecs="avc1.640028">
<Representation id="720p" bandwidth="2000000" width="1280" height="720">
<SegmentTemplate timescale="90000" duration="180000" ← 180000/90000 = 2秒
media="seg-$Number$.m4s" initialization="init.mp4"/>
</Representation>
<Representation id="1080p" bandwidth="5000000" width="1920" height="1080">...</Representation>
</AdaptationSet>
</Period>
</MPD>
SegmentTemplate は $Number$(インクリメントされる番号)または $Time$(タイムスタンプ)を使用してセグメントにアクセスします。リストにセグメントを一つずつ列挙する必要がないため、これはDASHがHLSのメディアプレイリストよりもコンパクトな理由です。低遅延DASH(LL-DASH)は CMAFチャンク + HTTPチャンク転送 を使用します。セグメント内部をさらにチャンクに分割し、エンコードされたチャンクをクライアントにチャンク転送で即座にプッシュし、セグメント全体のエンコード完了を待ちません。
CMAFの意義:HLSとDASHは長年それぞれ独自のセグメント形式を使用しており、CDNでは2つの形式を保存する必要がありました。CMAF (Common Media Application Format, fMP4) は、両者が同一のメディアセグメントセットを共有することを可能にします。リストのみが異なります(.m3u8 vs .mpd)→ 保存/キャッシュ量が半分になります。これが現在の事実上の収束方向です。
RTMP/RTMPS — 送信の生きた化石
AdobeがFlashのために設計し、TCPポート1935上で動作します。Flashは2020年に終了しましたが、RTMPは配信(ingest)プロトコルとして今も支配的です。すべてのエンコーダーとプラットフォームがデフォルトでサポートしています。
flowchart LR
OBS["🎥 OBS / モバイルアプリ<br><small>配信者側 1ストリーム</small>"] -->|"RTMP(S) ingest"| T["⚙️ <b>トランスコードサービス</b><br><small>複数ビットレートを出力<br>遅延とコストの大部分を占める</small>"]
T -->|"パッケージ化"| PKG["HLS / DASH"]
PKG --> CDN["🌍 CDN"] ==> V["千万単位の視聴者"]
classDef src fill:#64748b1f,stroke:#64748b,stroke-width:2px
classDef hot fill:#d2992226,stroke:#d29922,stroke-width:2.5px
classDef dist fill:#4493f81f,stroke:#4493f8,stroke-width:2px
class OBS src
class T hot
class PKG,CDN,V dist
トランスコードの部分は、全体のチェーンにおいて遅延とコストの大部分を占めます。プロトコルの重要なポイント:
- ハンドシェイク:C0/C1/C2 ↔ S0/S1/S2。バージョンとランダムなタイムスタンプ、エコーチェックを交換します。
- チャンク化:チャンクストリームは、オーディオ/ビデオ/メタデータを単一のTCP接続にマルチプレクスします(デフォルト128バイトのチャンク)。
- メタデータ/RPC:AMF (Action Message Format) で
connect/publish/onMetaDataなどをエンコードします。 - RTMPS = TLS上のRTMP。プラットフォームへの送信時の暗号化形態です。
RTMPは、技術的な先進性ではなくエコシステムの慣性によってingestを維持しています。SRTとWebRTCがこの領域を侵食しつつあります。
WebRTC — サブ秒のリアルタイム
ブラウザのリアルタイム通信のために設計され、ビデオ会議とインタラクティブライブ配信の事実上の標準です。エンドツーエンドの遅延は500ms未満になる可能性があります。単一のプロトコルではなく、スタックのセットです。
- シグナリング(アウトオブバンド、独自実装):SDP offer/answer を交換して、コーデックの能力とICE候補を交換します。
- NAT透過:ICEフレームワーク。STUNはパブリックIPに「私の外部アドレスは何ですか?」と問い合わせます(多くの場合、直接接続可能です)。TURNは、直接接続が失敗した場合のリレーとして機能します(帯域幅のコストがかかります)。
- 暗号化:DTLSハンドシェイクでキーを交渉し、SRTPでメディアを暗号化します。暗号化は必須で、プレーンテキストモードはありません。
- メディア:RTP/RTCPでオーディオ/ビデオを伝送します。輻輳制御にはGCC(Google Congestion Control)を使用し、パケット損失ではなく遅延勾配に基づきます。
WebRTCがHLSのようにCDNで展開するのが難しい理由:各接続はステートフルです(ICE/DTLS/SRTPのコンテキスト)。キャッシュ可能なファイルではありません。スケーリングはサーバートポロジに依存します。
flowchart TB
subgraph mesh ["😵 P2Pメッシュ — N²ストリーム、3〜4人にのみ適す"]
m1((A)) --- m2((B)) --- m3((C)) --- m1
end
subgraph sfu ["✅ SFU — メインストリームソリューション"]
s1((A)) -->|"アップリンク 1ストリーム"| S["<b>SFU</b><br><small>転送のみ、デコードなし</small>"]
s2((B)) --> S
S ==>|"オンデマンド配信"| s3((C))
end
subgraph mcu ["💸 MCU — CPUコストが非常に高く、廃止傾向"]
u1((A)) --> M["<b>MCU</b><br><small>デコード + 合成して1ストリームに</small>"]
u2((B)) --> M
M -->|"ミックスストリーム 1つ"| u3((C))
end
classDef good fill:#3fb95026,stroke:#3fb950,stroke-width:2.5px
classDef bad fill:#f851491f,stroke:#f85149,stroke-width:2px
classDef peer fill:#64748b1f,stroke:#64748b
class S good
class M bad
class m1,m2,m3,s1,s2,s3,u1,u2,u3 peer
| トポロジ | ストリーム数 | サーバーコスト | 結論 |
|---|---|---|---|
| P2Pメッシュ | N人が相互接続、N²ストリーム | サーバー不要 | 3〜4人以上で崩壊 |
| SFU(選択的転送) | 各ユーザーアップリンク1ストリーム、オンデマンド配信 | 転送のみ、CPU負荷低 | メインストリーム、スケーラブル |
| MCU(ミックス) | 各ユーザー1アップ1ダウン | デコード合成、CPUコスト非常に高 | ダウンストリーム帯域幅を節約、廃止傾向 |
詳細は WebRTC を参照してください。
SRT — 信頼できないネットワーク上の信頼できる送信
Haivisionがオープンソース化したもので、UDT(UDPベースのデータ転送)に基づいています。位置づけはパブリックインターネット/WANを横断する信頼性の高い低遅延伝送です。衛星回線やRTMPに代わって、スポーツの中継(contribution)で採用が進んでいます。
中核メカニズムは ARQ(選択的再送)+ 設定可能な遅延バッファ です。送信側は再送ウィンドウを維持し、受信側はパケット損失を検出するとNAKを送信し、損失したパケットのみを再送します。遅延バッファ(例:120ms)は、再送のための時間予算です。「わずかに遅延を増やす」ことで「パケット損失のあるリンクでの画質」を保証します。このレイテンシノブがSRTの真髄です。リンクが劣化すればするほど、値を大きく設定します。
- 暗号化:AES-128/256。
- 接続モード:Caller(アクティブ)/ Listener(パッシブ)/ Rendezvous(双方向同時開始、NAT透過用)。
RTMP(TCP、パケット損失がキューヘッドブロッキングを引き起こし、遅延が急増)と比較して、SRTはパケット損失のあるリンク上で非常に安定したパフォーマンスを発揮します。これが、ingest/contributionでの根本的な優位性です。
Moonlight/Sunshine — クラウドゲーミング/ストリーミング
NVIDIA GameStreamのオープンソース実装(Sunshineサーバー + Moonlightクライアント)。「リアルタイムレンダリングされたゲーム画面」を超低遅延のビデオストリームとして扱います。
flowchart LR
G["🎮 ゲームレンダリング<br><small>5-10ms</small>"] --> E["GPUエンコード<br><small>NVENC/AMF/VAAPI<br>5-10ms</small>"]
E ==>|"UDP上のRTP<br>+ FEC"| D["クライアントデコード<br><small>5-10ms</small>"]
D --> V["🖥️ ディスプレイ出力 VSYNC<br><small>5-15ms</small>"]
V -.->|"コントローラー/キーボード入力、振動フィードバック"| G
classDef host fill:#d299221f,stroke:#d29922,stroke-width:2px
classDef net fill:#4493f826,stroke:#4493f8,stroke-width:2px
classDef client fill:#3fb9501f,stroke:#3fb950,stroke-width:2px
class G,E host
class D,V client
LAN環境では、理想的なエンドツーエンドの遅延は20〜40msです。これは1.5フレーム未満の時間です。
なぜ再送ではなくUDP + FECを選択するのか:リアルタイムフレームのデッドラインは1フレーム分(60fps → 16ms)しかありません。再送の往復を待っていると、必ずディスプレイ出力のタイミングを逃します。再送されてきたフレームはもう役に立ちません。そのため、フォワードエラー修正(FEC、Reed-Solomon)を使用します。冗長パケットを多数送信し、少量のパケット損失でもローカルで直接復元し、往復ゼロで済ませます。さらに、フレームパシング(pacing)を組み合わせてディスプレイ出力を滑らかにし、ジッターを回避します。
プロトコル選択
| 要件 | 優先候補 | 主要な理由 |
|---|---|---|
| VOD / 大規模ライブ配信 | HLS または DASH (CMAF) | CDNでキャッシュ可能、コスト最小 |
| Appleエコシステム優先 | HLS | ネイティブサポートが最良 |
| 低遅延スポーツライブ配信 (1-2秒) | LL-HLS / LL-DASH | CDNを維持し、わずかな遅延を犠牲に |
| ビデオ会議 / インタラクティブ (<500ms) | WebRTC (SFU) | リアルタイムだが、ステートフルでCDN展開が困難 |
| パブリックインターネット経由の送信回線 | SRT | パケット損失リンク上で安定、遅延調整可能 |
| ライブ配信プラットフォームへの送信 (ingest) | RTMP(互換性)/ SRT | エコシステムの慣性 / パケット損失耐性 |
| クラウドゲーミング / リモートデスクトップ | Moonlight / WebRTC | フレームレベルの遅延 + FEC |
参考
- HLS: developer.apple.com/streaming (LL-HLS仕様を含む)
- DASH: dashif.org · ISO/IEC 23009-1
- WebRTC: webrtc.org · RFC 8825 シリーズ
- SRT: github.com/Haivision/srt
- Sunshine: github.com/LizardByte/Sunshine
- 参考実装: hls.js · dash.js (ABRアルゴリズムの産業標準実装。ソースコードを読む価値あり)
Keywords: HLS, LL-HLS, DASH, CMAF, ABR, BOLA, RTMP, WebRTC, SFU, ICE, SRT, ARQ, Moonlight, Sunshine, NVENC, FEC, adaptive bitrate