m3u8 ファイルの中身を読む — 開発者のためのデバッグ完全ガイド 2026 年版
HLS の配信トラブルで Chrome DevTools を開いたら、最初に見る相手は決まって master.m3u8 です。けれど、その中身を「なんとなく」読んでいると、シーク不能・再生中断・鍵取得失敗のような事故は必ず再発します。本記事では、フロントエンドエンジニアと配信インフラ担当者に向けて、m3u8 とは何か、#EXT-X- タグはどこを見れば良いか、そして CMAF / fMP4 / MPEG-TS の選び分けで何が変わるのかを、実ファイルとともに掘り下げます。
1. m3u8 ファイルの正体 — UTF-8 必須のプレイリスト
m3u8 とは、Apple が策定した HLS(HTTP Live Streaming)で使われるプレイリストファイルそのものです。仕様は IETF の RFC 8216、最新の拡張は Apple HLS Authoring Specification(2024-09 改訂版)にまとまっています。中身は単なるテキストで、UTF-8 エンコード必須、BOM はあっても無くても良いが行末は LF または CRLF、各行が #EXT から始まるタグ行か、セグメントの URI を指すURI 行かのいずれかです。
最重要の前提は 3 つです。1 行目は必ず #EXTM3U、文字コードは UTF-8、URI 行はメディアセグメント(.ts / .m4s)または下位プレイリスト(.m3u8)への絶対 URL か相対 URL のいずれか。これを満たさないと、Safari は無言で再生を諦めます。逆に言えば、再生不能の調査はこの 3 点の照合から始めれば 8 割は片付きます。
2. master playlist と media playlist — 二層構造を区別する
HLS は二層プレイリストで成り立っています。**master playlist(マスター)**は複数のレンディション(解像度・ビットレート違い、音声トラック、字幕)を束ねるインデックスで、再生プレイヤーはここから ABR の候補を選びます。**media playlist(メディア)**は実際のセグメント .ts / .m4s を時系列で並べた一次元のリストで、#EXTINF の継ぎ合わせがそのまま再生時間軸になります。
master の典型例は次のとおりです。
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-INDEPENDENT-SEGMENTS
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aac",NAME="Japanese",DEFAULT=YES,LANGUAGE="ja",URI="audio/ja/playlist.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=2800000,AVERAGE-BANDWIDTH=2400000,CODECS="avc1.640028,mp4a.40.2",RESOLUTION=1920x1080,FRAME-RATE=30.000,AUDIO="aac"
video/1080p/playlist.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1400000,CODECS="avc1.4d401f,mp4a.40.2",RESOLUTION=1280x720,FRAME-RATE=30.000,AUDIO="aac"
video/720p/playlist.m3u8
このファイルの URI 行は再びプレイリスト(media playlist)を指します。一方 media playlist の中身は次のように、#EXTINF とセグメント URI が交互に並ぶだけのフラットな構造です。
#EXTM3U
#EXT-X-VERSION:7
#EXT-X-TARGETDURATION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MAP:URI="init.mp4"
#EXTINF:6.000,
seg-00001.m4s
#EXTINF:6.000,
seg-00002.m4s
#EXTINF:5.840,
seg-00003.m4s
#EXT-X-ENDLIST
master を media と勘違いしてセグメント URL を直接叩こうとする事故は、新人レビューでよく見かけます。区別の最短ルートは「#EXT-X-STREAM-INF を含むなら master、#EXTINF を含むなら media」と覚えること。両方を兼ねることは仕様上できません。
3. 主要な #EXT-X- タグ徹底解説
タグは大別して 3 系統あります — マスター専用、メディア専用、双方共通。デバッグで頻出するものに絞って整理します。
双方共通:#EXT-X-VERSION はファイル全体の最低互換バージョン。fMP4(.m4s)を使うなら 6 以上、SAMPLE-AES なら 5 以上、EXT-X-INDEPENDENT-SEGMENTS を使うなら 6 以上が必要です。古い iOS(13 以前)は version 7 まで、EXT-X-DEFINE などの新タグは version 8 以上で評価されます。
media playlist 必須:#EXT-X-TARGETDURATION は最大セグメント長の整数値。実セグメントがこれを 1 秒でも超えると Apple HLS Validator は警告し、Safari は再生を停止することがあります。#EXT-X-MEDIA-SEQUENCE は live HLS でセグメントが押し出される起点番号、VOD では基本 0。#EXT-X-PLAYLIST-TYPE は VOD か EVENT。#EXT-X-ENDLIST は VOD の終端マーカで、これが無いとプレイヤーは「ライブ更新を待ち続ける」モードに入ります。
fMP4 専用:#EXT-X-MAP は init segment(moov ボックス)の URI。fMP4 では必須、TS では不要。BYTERANGE 属性で 1 ファイルに init を埋め込むことも可能ですが、CDN キャッシュ効率は悪化します。
ライブ・DVR 制御:#EXT-X-DISCONTINUITY は次セグメントでタイムスタンプ・コーデック・解像度が切り替わる宣言。広告挿入(SCTE-35)や複数素材結合で多用されます。#EXT-X-DISCONTINUITY-SEQUENCE はライブ巻き戻し時の追跡用。
暗号化:#EXT-X-KEY は AES-128 や SAMPLE-AES のキー URI と IV。URI="" の空文字は「以降は暗号化なし」の意味で、プレイヤーごとに解釈が違うため事故源です。Widevine は KEYFORMAT="urn:uuid:edef8ba9-..." で識別します。
マスター専用:#EXT-X-STREAM-INF は ABR レンディション宣言、BANDWIDTH はビット/秒の整数で必須、CODECS は RFC 6381 形式(avc1.640028,mp4a.40.2 のような)で、ここを誤るとプレイヤーは「対応コーデック無し」と判定して落ちます。#EXT-X-MEDIA は代替音声・字幕・ビデオの宣言、TYPE(AUDIO / SUBTITLES / CLOSED-CAPTIONS / VIDEO)と GROUP-ID の対応関係が肝です。
性能ヒント:#EXT-X-INDEPENDENT-SEGMENTS は「全セグメントが IDR フレームから始まる」保証。これが master か media のどちらか上位に書かれていれば、プレイヤーはセグメント先頭から無条件にデコード開始できます。#EXT-X-I-FRAMES-ONLY は trick play(早送り・サムネ用)の I フレームのみのプレイリスト。
m3u8-info では、これらタグを階層ツリーで可視化し、必須属性の欠落や VERSION 不整合をハイライトで指摘します。
4. CMAF と fMP4、MPEG-TS — セグメントコンテナの違い
セグメントの中身は HLS の歴史で 3 系統に分かれます。比較表で整理します。
| 項目 | MPEG-TS(.ts) | fMP4(.m4s) | CMAF(.cmfv / .m4s) |
|---|---|---|---|
| 仕様 | ISO/IEC 13818-1 | ISO/IEC 14496-12 (fragmented) | MPEG-A Part 19 |
| HLS 対応 | 1.0〜(最古) | HLS v6 以降(2016〜) | HLS v7 以降(2017〜) |
| DASH 互換 | 不可 | 部分的 | 完全互換(CTE で同セグメント) |
| 188 byte パケット境界 | あり | なし | なし |
| init segment | 不要(PAT/PMT で自己記述) | 必須(#EXT-X-MAP) | 必須(#EXT-X-MAP) |
| 字幕埋め込み | EIA-608/708 | WebVTT or TTML | WebVTT or TTML |
| 暗号化 | AES-128 / SAMPLE-AES | SAMPLE-AES + cbcs | cbcs 標準(DASH と共通鍵) |
| 推奨用途 | レガシー配信 | iOS 専用 | HLS+DASH 同時配信 |
判断基準:iOS 11 以前のサポートが必要なら TS、それ以外で iOS 専用なら fMP4、HLS と DASH を同時配信するなら CMAF を選びます。CMAF は要するに「DASH と HLS が同じセグメントファイルを共有できる fMP4 のサブセット」と理解すれば良く、ストレージと CDN コストが半減するため、2026 年現在の新規プロジェクトの第一候補です。
注意点として、Mediabunny 1.44 が出力する HLS は単一レンディションの fMP4 ベースで、ABR は再生側に任せる設計です。cutfa.st 自身はブラウザだけで動くため、サーバー側で複数ビットレートを生成するパイプラインを組みたい場合は別途 ffmpeg などが必要になります。
5. よくある不具合パターン — 実例で読み解く
INDEPENDENT-SEGMENTS なしでシーク不能:master にも media にも #EXT-X-INDEPENDENT-SEGMENTS を書き忘れると、プレイヤーはセグメントの先頭が IDR フレームかどうか判定できず、シークバーをドラッグした瞬間に映像が灰色になる症状が出ます。Safari は特に厳格で、hls.js は寛容ですがバッファリング時間が伸びます。
TARGETDURATION 過小:#EXT-X-TARGETDURATION:4 と書いたのに実セグメントが #EXTINF:4.5, のように 4 秒を超えると、Apple HLS Validator は ERROR を返し、Safari の MediaError.MEDIA_ERR_DECODE で再生中断します。整数切り上げで TARGETDURATION ≥ max(EXTINF) の不等式を必ず満たすこと。
KEY 取得失敗:#EXT-X-KEY:URI="https://drm.example.com/key/123" の URL が CORS なしで配信されると、ブラウザ HLS(hls.js)は keyLoadError で落ちます。Access-Control-Allow-Origin: * か特定オリジンを必ず返すこと。Safari ネイティブはクッキーでの認証もサポートしますが、hls.js は明示ヘッダ付与を xhrSetup で書く必要があります。
CMAF と TS の混在:#EXT-X-DISCONTINUITY 経由で .ts と .m4s を交互に並べる構造は仕様上は通っても、多くのプレイヤーで「コーデック切替遅延」によるブラックフレームを引き起こします。同一プレイリスト内でコンテナを混ぜないのが鉄則です。
MEDIA-SEQUENCE と DVR 巻き戻し:ライブで #EXT-X-MEDIA-SEQUENCE を再起動時にリセットしてしまうと、視聴者側は「同じシーケンス番号で違うセグメント」を受け取り、巻き戻し時にフリーズします。CDN とエンコーダの間で sequence は単調増加を保つ。
これらの症状を一発で見抜くために、m3u8-player では実プレイリストをドラッグドロップで読み込み、タイムラインと共に DISCONTINUITY、KEY、MAP のマーカを重ね描画します。
6. ブラウザだけでパースする手順 — cutfa.st m3u8-info
m3u8 のパース自体は単純な行ベース処理なので、わざわざサーバーに上げて解析する必要はありません。cutfa.st の m3u8-info は Mediabunny 1.44 の HLS 読み取り機能を直接ブラウザ上で叩き、master.m3u8 を投げ込むだけで以下を抽出します。
- タグ階層ツリー:master/media の二層を折りたたみ表示、各タグの仕様準拠チェック
- レンディションマトリクス:解像度・ビットレート・コーデック・音声トラックの対応表
- セグメント時系列:
EXTINF値の分布グラフ、TARGETDURATION違反の赤マーク - 暗号化情報:
KEYのMETHOD/KEYFORMAT/IVを解析、URL の CORS 状態をプリチェック - 互換性レポート:iOS 13 / Safari 17 / hls.js / shaka-player でそれぞれ再生可能か
- エクスポート:解析結果を JSON でダウンロード、CI に組み込み可能
ファイルはアップロードされません。WebCodecs と File API でローカル処理されるため、社外秘の DRM 設定や内部 CDN URL を含むプレイリストでも安心して投げられます。一方、現在は WebVTT 字幕のミックスと DRM パッケージング出力には未対応で、これらは ffmpeg や Bento4 などのサーバー側ツールに頼る必要があります。
7. デバッグツールチェイン — 用途別の使い分け
ブラウザ完結ツールでは届かない領域は、専用 CLI に落とすのが正解です。
mediainfo CLI:個別セグメント .ts / .m4s のコーデックパラメータを見る。mediainfo --Inform="Video;%CodecID%,%Width%,%Height%,%FrameRate%" seg.m4s で 1 行で取り出せます。
ffprobe:時間軸の連続性確認に最適。ffprobe -show_packets -select_streams v:0 seg.ts | grep pts_time で PTS 不連続を発見できます。
Apple HTTP Live Streaming Tools:macOS 限定、mediastreamvalidator master.m3u8 が事実上の最終判定。Apple App Store 申請でも使われる検証器で、警告 0 / エラー 0 を目指す価値があります。
Charles Proxy / mitmproxy:実機 iOS / Android で Range: ヘッダの実際の挙動、KEY 取得時の Cookie、CDN のキャッシュヒット率を傍受。
Wireshark:CMAF Low-Latency HLS(LL-HLS)でチャンク転送(Transfer-Encoding: chunked)が想定通り効いているかをパケットレベルで確認。
hls-validator(npm):CI に組み込みやすい Node 製。GitHub Actions で master playlist の構造を毎ビルドで検証できます。
CDN 側の調査が必要なら、Cloudflare の cf-cache-status ヘッダ、Akamai の X-Cache ヘッダ、AWS CloudFront の X-Cache: Hit from cloudfront の有無を必ずチェック。再生不能の根本原因が「セグメントが返っていない」だけのこともよくあります。
ローカルで生成した HLS をすぐ確認したいなら HLS converter で MP4 から fMP4 ベースの単一レンディション HLS を出力し、それを m3u8-info と m3u8-player に通してから本番アップロードする、という閉じたループが最速です。
FAQ
Q1. CMAF と fMP4 の違いは何ですか?
A. CMAF は fMP4 のサブセットで、HLS と DASH が同じセグメントファイルを共有できるよう制約を課したものです。具体的には cbcs 暗号化スキーマの採用、init と media の分離、特定の box 順序などが規定されており、結果として 1 本のエンコードで両プロトコル配信が可能になります。
Q2. HLS のバージョン互換はどこで切れますか?
A. iOS 13 までは v7、iOS 14 以降は v9 まで安全です。EXT-X-DEFINE(v8)や EXT-X-PRELOAD-HINT(LL-HLS、v9)を使うとそれ以前のクライアントで無視され、最悪パースエラーになります。#EXT-X-VERSION は使うタグの中で最も新しい必要バージョンに合わせること。
Q3. 低遅延 HLS(LL-HLS)は cutfa.st で生成できますか?
A. できません。Mediabunny 1.44 の HlsOutputFormat は VOD 向け単一レンディション fMP4 のみで、EXT-X-PART などの LL-HLS タグは未実装です。Apple の mediastreamsegmenter か Wowza、AWS MediaPackage を使う必要があります。
Q4. Apple App Store 認証で必須の HLS 要件は?
A. RFC 8216 準拠、mediastreamvalidator 警告 0、最低でも 192kbps のオーディオ専用レンディションを 1 本含む、#EXT-X-INDEPENDENT-SEGMENTS 推奨、です。実写動画のセルラー再生で 192kbps 未満は審査で弾かれた事例があります。
Q5. Widevine と SAMPLE-AES の違いは?
A. SAMPLE-AES は Apple HLS 独自の AES-128 ベース暗号で、KEYFORMAT="com.apple.streamingkeydelivery" 系で運用されます。Widevine は Google の DRM で KEYFORMAT="urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"、ライセンスサーバーが必要。Apple デバイス専用なら SAMPLE-AES、Android / Web 同時対応なら Widevine + FairPlay の同時パッケージングが定番です。cutfa.st は DRM 出力には未対応で、読み取り専用のメタデータ解析にとどまります。
Q6. #EXT-X-DATERANGE は何に使いますか?
A. 広告挿入(SCTE-35)、ライブイベントの章立て、メタデータ通知に使うタグです。ID、START-DATE、DURATION、SCTE35-OUT などの属性で「この時刻から N 秒間は広告ブレーク」のような指示をプレイヤーに渡します。広告 SDK との連携で必須となるケースが多く、IAB OpenMeasurement との組み合わせで視聴計測も可能になります。
m3u8 は単純なテキストですが、各タグの裏には Apple と IETF の長い設計議論があります。読み解けるようになると、CDN ログを見るだけで「あ、これは TARGETDURATION 違反だ」と即断できるようになり、配信トラブルの解決速度が一桁変わります。実ファイルを手元で観察するところから始めてみてください。
このシリーズの他の記事
「HLS・m3u8・配信録画」の記事 8 本をすべて見る →