HTML側の対応やWebアプリ側の対応をしたにもかかわらず、動画が流れなかったので散々調べて解消しました。
前提
- 動画ファイルの拡張子はmp4
- videoタグを使って、動画を再生させる
- ブラウザから動画ファイルを直接参照させるのではなく、Webアプリ側の関数で取得したファイルをバイナリのレスポンスとして返す
現象
- Safariだけで動画が流れない
- Webサーバー配下に同じ動画ファイルを配置して直接参照をさせると、Safariでも流れる
考えられる原因
大きく分けて、以下の3つが原因として考えられます。
- videoタグの属性が正しくない
- Webアプリからのレスポンスが、HTTPのRangeヘッダを使った範囲リクエストに対応していない
- mp4ファイルが、ストリーミング再生に対応していない
videoタグの属性を見直す
iOSの場合、動画を再生させるためには、playsinline 属性が必須です。
また、動画を自動再生させる場合は、音ありでの自動再生はできません。ユーザーがブラウザを操作しているときに、予期せず音が流れ出すことを防ぐためです。
そのため、autoplay 属性とmuted 属性はセットで使用することになります。
iOSで動画を自動再生させたい場合には、playsinline autoplay muted を3つセットで使う必要があります。
Webアプリのレスポンスを見直す
iOSの場合、動画ファイルを読み込む際には大きなファイルのダウンロードを防ぐために、HTTPのRangeヘッダフィールドを使った範囲リクエストが使われます。
この範囲リクエストに対応していない場合、ブラウザ側は動画の読み込みを中断するという仕様になっています。
iOSから送られてくるリクエストは以下のようになります。
- 範囲リクエストを用いて、0-1バイトのリクエストを呼び出す
- レスポンスからWebアプリが範囲リクエストに対応しているかを判断
対応していない場合、処理を終了 - 動画の総サイズを見て、範囲リクエストを投げて動画の一部を取得する
※開発者ツール(Webインスペクタ)でリクエスト、レスポンスの内容を参照すると、範囲リクエストの流れを追うことができます。
範囲リクエストに対応するレスポンスには、HTTPヘッダやレスポンスのステータスコードにいくつかの制約があります。詳しくは、上記Mozillaのサイトを参照してください。
mp4ファイルを見直す
ここまでの内容をすべて入れたにもかかわらず、iOSで動画が再生されないという場合は、もしかしたらここに課題があるのかもしれません。
特に、aviファイルをmp4ファイルに変換している場合など、もともと他の形式だった動画をffmpeg等を使って変換したときには、ここの内容に従って変換方法をみなす必要があるかもしれません。
前述のように、iOSでは動画のダウンロードで範囲リクエストが用いられます。そのため、動画ファイルは分割されても再生可能な形式になっている必要があります。
具体的には、mp4ファイルは以下の2点を満たす必要があります。
- 走査方式が、プログレッシブ方式であること
- moov atom(動画のメタデータ)が、ファイルの先頭にあること
動画ファイルがバイト単位で分割されることを考えると、インターレース方式にせずに1枚の画像を一度に表示させたり、メタ情報を先頭に置いて動画の概要を取得させたりする必要があるということです。
これに対応できていないmp4ファイルなのであれば、ffmpeg等を利用して動画を変換することで再生可能となります。
これでも再生されない場合は・・・
私は、この対応で動画が再生されることを確認できましたが、これでも再生されない場合は、HTMLと範囲リクエストへの対応といったWeb側の問題というよりは、mp4ファイル側の問題ではないかと思われます。
コーデックやプロファイル、レベルが対応しているかを地道に確認していくしかないかと。。。