最近、スマホやタブレットを使う機会も多いですが、その辺りの端末に動画コンテンツを提供する時に楽なのがmp4形式の動画をvideoタグで貼り付ける事です。
ただ、ちょっとした注意点があって、どういう状況で再生するかによって細かい調整をしておかないと、再生開始までにえらく時間がかかるようになって、非常に不便になります。
既に作成済みの動画を再生する場合
mp4形式の動画を再生するためにはメタデータ情報が必要です。メタデータは通常ファイルの末尾に付与されます。ファイルサイズが小さい時は気付かないのですが、10分、20分ぐらいあるような動画を再生しようとすると末尾まで読んでから再生できるかどうかを判別するので、再生が開始できるようになるまでに異様に時間がかかるようになります。
そこで動画作成時にメタデータをファイルの先頭に移動させておきます。
こうする事で、ファイルサイズが大きい動画でも一瞬で再生開始が可能になります。
PCのブラウザだと、その辺上手いことやってくれるのか末尾にメタデータがあってもすぐに再生できたりするんですが…。
ffmpegで動画を作成している場合には、-movflags faststart
オプションを利用することでエンコード後にメタデータを先頭に移動させる事ができます。
例としてはこんな感じ。
ffmpeg -i inputfile -f mp4 -vcodec libx264 -b:v 800k -acodec libfaac -b:a 128k -movflags faststart -o output.mp4
既に存在しているmp4を変換したい場合はqt-faststartというツールが利用できます。
エンコードしながら追っ掛けて再生する場合
バックグラウンドでエンコードしつつ動画の再生を開始したい場合、PC向けかモバイル向けかで状況が変わります。
モバイル向けの場合
モバイル端末で追っ掛けながら再生する場合はHTTP Live Streaming(HLS)を使うのが良い方法です。
HLSは動画ファイルを約10秒程度の短時間に分割しMPEG-TSコンテナに入れたものをひたすら生成しつつm3u8形式のリストファイルにそのファイルを逐次追加していくことで、HTTPのみで擬似的にLive Streamingを実現する方法です。
Appleが提唱したらしく、iOSが最も安定して再生できるのですが一応Androidでも対応します。
(手元のNexus7で試した所、Androidだとシークが出来なくなる)
HLSを利用することで、Webカメラ等で録画しつつHTML5のvideoタグで配信する、といった事も可能になりますし、オンデマンドで動画ファイルを変換しながら再生するということもWebブラウザだけで実現可能です。
以前は動画の分割がかなり面倒だったのですが、新しめのffmpegであればsegment分割の機能が組込まれているので、簡単に作成することができるようになりました。
ffmpegでHLSを作成するには以下のように設定します。
ffmpeg -i inputfile -vcodec libx264 -b:v 800k -acodec libfaac -b:a 128k -flags +loop-global_header -map 0 -bsf h264_mp4toannexb -f segment -segment_format mpegts -segment_time 10 -segment_list output.m3u8 stream%04d.ts
自分が試した時には、何故か-flags +loop-global_header
と-map 0
と-bsf h264_mp4toannexb
のオプションが必要になりましたが、詳しい理由は不明です。
重要なのは以下のオプションです。
-
-f
で出力形式をsegment
に指定する -
-segment_format
で分割されたストリームのフォーマットをmpegts
に指定する -
-segment_time
で分割単位時間を指定する。大体10秒くらいが目安らしい -
-segment_list
で出力するリストファイル名を指定する - 出力名に連番が振られるように
%04d
等を含めておく。この場合4桁の連番になる。
videoタグには出力されたm3u8ファイルを指定しておきましょう。
HLSでwebカメラの映像等を配信している場合、そのままだとガンガンファイルが溜まっていってストレージを圧迫するので、不要になったデータを定期的に削除する仕組みが必要になるかもしれません。
PC向けの場合
PC向けのブラウザでは今のところSafariを除いてHLS形式の再生は不可能です。
ちゃんとストリーミングサーバーを用意してrtpなりrtspなりのプロトコルを利用すれば再生できそうですが、中々面倒そうなのでこちらは試していません。一応videoタグでも利用できそうですが未検証です。
インチキな解決策として、fragmented mp4を作成するという方法があります。
通常mp4のメタデータは一箇所にまとめて配置されますが、それをキーフレームごとに分散して配置する方法です。
こうしておくとエンコードが全て終わっていなくても、現在エンコードが進んでいる所までは再生できるようになります。ただ一回読み込んだ時点で動画の長さが認識されるので、途中で止まってしまった場合続きを再生できるようにするには再読み込みが必要です。
一瞬停止しても良いならJSを組み合わせてゴリ押すことも可能かもしれませんが、中々面倒です。
fragmented mp4を作成するのもffmpegでオプションを追加するだけでOKです。
ffmpeg -i inputfile -f mp4 -vcodec libx264 -b:v 800k -acodec libfaac -b:a 128k -movflags frag_keyframe -o output.mp4
というわけで、html5のvideoタグを利用した動画の配信はiOS系が一番進んでいるような気がします。AirPlayも利用できるので、Apple TVがあれば普通にテレビに転送して再生できたりします。
自宅にカメラ置いてモニタするWebシステムを作りたい時とか、自宅のストレージにある動画をどこでも見れるようにしたい時に使えると思います。
まあ、そういう既存のアプリもあるので普通そっち使うのが良いと思いますが、細かい部分を自分に便利な形にしようとすると自分で色々用意するのが結局楽だったりします。