HLS規格での動画配信デバッグ 備忘録
#動画SEO #HLS #m3u8

様々なデバイスで撮影された動画ファイルをHLS形式で配信するためには適切なHLS変換が不可欠となる。 動画でのコンテンツ配信時代において必須の知識であるHLS動画配信規格完全理解のための備忘録。ビヨンドウェブのHLS動画配信モジュール開発の中での学びを常時更新していきます。
HLSとは?
HLS (HTTP Live Streaming) は、Apple社が開発した動画ストリーミング配信規格で、インターネット経由での動画配信や音楽配信に広く使われています。HLSは、動画ファイルを小さなチャンク(セグメント)に分割し、HTTPプロトコルで配信します。これにより、視聴者のネットワーク状況に合わせて最適な画質を選択できるアダプティブビットレートに対応し、スムーズな再生を実現します。
この記事では、まず、実際に起きた再生エラーへの対応時のポイントを備忘録として以下にまとめます。
発生した難解な問題
Pixel9などのスマートフォンで画像撮影の長押しで録画したファイルがHLS変換・配信後、PCブラウザでは問題なく配信されるにも関わらず、androidスマートフォンのChromeブラウザでは再生直後に再生が停止してしまう現象が確認された。iphoneのsafariやchromeブラウザでは問題なく再生された。
またこの問題は、プレイヤー側のコードで以下を実施するもエラーは出力されない(再生エラーではない)
hls.on(Hls.Events.ERROR, (_, data) => {
console.error("HLS.js error:", data);
});
疑わしいこと
- 変動フレームレート(VFR)によるセグメント長のズレ
Pixel シリーズは高ビットレート・可変フレームレート(Variable Frame Rate)で録画することが多い - 不規則なGOP(キーフレーム)配置
Pixel 9 のソース動画はデフォルトだと「シーン切り替えに応じて」キーフレームを打つ傾向があり、固定間隔ではない
マニフェスト(.m3u8)の確認
マニュフェストの中身を表示
less output.m3u8
中身:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:8
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:8.333333,
output0.ts
#EXTINF:5.166667,
output1.ts
#EXT-X-ENDLIST
問題がなさそう。#EXTINFが#EXT-X-TARGETDURATIONの8を超えているのが不自然に思ったがこれは他の問題のない動画でも同様であったため、問題無いと思われる。
セグメントのフレームレートとキーフレーム位置を調べる
各 .ts セグメントの先頭にキーフレーム(IDR)があるか、ffprobe で確認する。
# セグメント 0 の先頭フレームのみ抽出して key_frame フラグを確認
ffprobe -v error \
-select_streams v \
-show_frames \
-read_intervals "%+1" \
-print_format json \
segment0.ts \
| jq '.frames[0] | {pkt_pts_time, key_frame, pict_type}'
出力:
{
"pkt_pts_time": "1.466667",
"key_frame": 1,
"pict_type": "I"
}
ここに問題がありそう!
最初のキーフレーム(I-フレーム)がセグメントの先頭ではなく、約1.47秒時点にしか現れていない。HLS(特にネイティブ HLS)では、各 TS セグメントの先頭に IDR(独立した I-フレーム)がないと、デコーダが参照フレームを得られず再生開始時に停止してしまう。
pkt_pts_time(Presentation Timestamp)
FFprobe 等のツールで出力されるメタデータ項目で、そのフレーム(またはパケット)が「再生タイミング上でいつ表示されるか」を秒数(小数)で示したものです。pkt_pts_time: "1.466667" なら、「再生タイムライン上で 1.466667 秒地点に表示されるフレーム」という意味。
つまり、今回のファイルでは1.47秒までフレームが何もない状態となり、問題が発生していたと考えられる。
対策
以下の項目をffmpegコマンドに追加して解決を試みるも、問題は解消されず。
"-g", "120", # GOP長を120フレーム(約4秒)に固定
"-sc_threshold", "0", # シーンカット検出を無効化
"-force_key_frames", "expr:gte(t,n_forced*4)",
"-hls_flags", "independent_segments",
一旦の結論
今回の実装変更では他の動画にも良い影響を及ぼすためこのまま実装するが、発生している問題は解決できず。Pixelフォーンで通常の動画撮影モードで撮影したものは問題なく再生されるため。Pixelフォーンの画像長押しモードでの撮影での動画は現状非対応とする。
今後、他の動画で同じ問題が発生すれば再度調査開始する。

真屋 明典
ビヨンドウェブ開発者(TensorFlow認定開発者) 起業家・国内外で15期連続黒字企業経営