GOP長を調整して素早くシークができるようにする
さて、上記で作ったファイルを再度簡易HTTPサーバーで再生してみましょう。
<!DOCTYPE html>
<html>
<head>
<title>Test streaming player</title>
</head>
<body>
<video src="output_1080p.mp4" controls></video>
</body>
</html>
どうでしょう?快適に再生できたでしょうか?ローカルサーバーからの参照なので当然快適に再生できることでしょう。
せっかくなので、実際のユーザー環境に近づけてみます。各種Webブラウザには開発者ツールに通信速度をシミュレートする設定があるため、そちらを有効にして、ユーザーの回線環境を再現してみます。
例として以下にGoogle Chromeでその設定を行う方法を紹介します。
まず、開発者ツールを下記コマンドで起動します。
- macOS:command⌘ + option⌥ + I
- Windows:Ctrl + Shift + I
次に「Network」タブを選択し、WiFiマークをクリックします。すると画面下方に「Network Conditions」タブが表示されるため、そこの「Network throttling」の設定を変更してみましょう。

例では「10Mbps」で通信を行う設定を追加して、利用しています。

この状態で何度かシークを実行してみましょう。1秒~2秒ほどシークに時間が掛かることがあると思います。
この原因は先程のコマンドで指定した、「-g 120」と「-sc_threshold 0」によって、強制的にGOP(Group Of Pictures)の長さが120フレーム(=4秒)に設定されていたためです。
動画の圧縮に用いられている要素技術の一つとして、フレーム間の差分に注目し、フレーム間で変化していない部分をなるべく同じデータで表現するという方法があります。GOPはそれらをまとめる単位のことだと思って差し支えありません。
例えば、GOP長が4秒であった場合、4秒ごとに「キーフレーム」と呼ばれる「そのフレームデータのみでデコードが可能なフレーム」が挿入されており、それ以外のフレームは前後(通常は前)のフレームを参照しなければデコードできないフレームとなっています。すなわちシークした場合は最大4秒前のフレームからデータを参照しないとデコードができないことになります。
今回の例では6Mbpsでエンコードしていたため、4秒だと24Mbとなります。回線速度を10Mbpsに指定していたため、最大2.4秒程度バッファリングが発生することになります。
なお、キーフレームはなるべくシーンの変わり目に挿入するほうが良いとされています。その方が差分を計算する上で有利となり、圧縮率向上が狙えるからです。libx264には強力なシーンチェンジ検出機能が搭載されており、デフォルトでシーンチェンジの位置にキーフレームが挿入されるような設定になっています。「-sc_threshold」はシーンチェンジ検出の設定を行うオプションであり、上記例では「0」を指定することでそれらを無効にしていました。
では今度はGOP長が1秒程度の動画を作ってみましょう。「-g 30」とすることで1秒ごとにキーフレームが入るようにしており、なおかつ「-sc_threshold 0」を削除することでシーンチェンジも加味した形で良い塩梅に挿入されるようになります。
$ ffmpeg -i bbb_sunflower_1080p_60fps_normal.mp4 -c:v libx264 -preset veryslow -r 30 -g 30 -s 1920x1080 -b:v 6000k -maxrate 8500k -bufsize 8500k -level 42 -pix_fmt yuv420p -aspect 16:9 -sar 1:1 -c:a aac -b:a 128k -ac 2 -movflags +faststart output_1080p_gop30.mp4
HTMLファイルを下記のように編集し、それぞれの動画を見比べてみましょう。
<!DOCTYPE html>
<html>
<head>
<title>Test streaming player</title>
</head>
<body>
<video src="output_1080p.mp4" controls></video>
<video src="output_1080p_gop30.mp4" controls></video>
</body>
</html>
明らかに後者の方が快適にシークができると思います。
このようにGOP長を短くする事でシークの体験を向上させることができます。
ではストリーミング配信においてはGOP長はなるべく短いほうが良いのでしょうか?残念ながらそういった単純な判断は難しいパラメーターとなっています。
一般的にGOP長は長ければ長いほど圧縮効率が高くなる可能性があるとされています。そのため、ストリーミング配信におけるGOP長の長さは、圧縮効率とシーク体験のトレードオフとなっているといえます。
シークが多く発生するようなコンテンツのストリーミング配信では、0.5~2秒程度のGOP長が望ましいことでしょう。逆にシークすることがあまり考えられないコンテンツにおいては、シーンチェンジをベースとした10秒前後のGOP長でも問題なくサービス提供できる可能性があります。
このあたりはサービスの性質やコンテンツの性質も加味した上で判断する必要があります。
なお、これは経験則ではありますが、短すぎるGOP長(10フレーム未満な値)はストリーミング再生においては再生を不安定にする可能性があります。逆にGOP長が長くなればなるほど、デコード時のバッファサイズを要するため、クライアントのスペックを加味すると長すぎるのも良くないと言えます。
そのため、0.5~10秒程度のGOP長が望ましいと思われます。
