それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

ffmpeg で mp4 をiPhone用のストリーミング(HLS)に対応させる。

mp4 を iOS で見るには。

Apacheで動画ファイルを配信するのが一番楽なんですが。

iOSSafariは、動画ファイル先頭だけ読み込んで、mp4のメタデータ無ければ末尾を取りに行きます。

これが、ネットワークが貧弱なときに時間がかかってしまって結構辛い。

とくに AirPlay をAppleTVでやってると読込時間で疲れてしまう。

 HLSで動画を部分的に分割して読み込ませる。

HLS は Apple が定義している動画の分割ダウンロードの仕組み。

mp4 を TS にして配信するだけじゃなく、シークや巻き戻し時に、HTTP経由で分割済みのファイルをダウンロードしてくる。

ts は h264 と aac が対応していて、一番良く使うと思う。

ffmpeg で HLS ファイルを作る

/usr/local/bin/ffmpeg -i  input.mpeg  -vcodec libx264 \
  -s 1280x720 \
  -acodec libfaac -b:a 256k\
  -flags +loop-global_header \
  -bsf h264_mp4toannexb \
  -f segment -segment_format mpegts \
  -segment_time 10 \
  -segment_list happy.m3u8 happy_%04d.ts

動画解像度のサイズやビットレートは変えても大丈夫。

オプションについて。

  • -bsf h264_mp4toannexb bsf は ビットストリーム出力の指定。 h264_mp4toannexb がmp4のストリーミング
  • -flags +loop-global_header mp4 のメタデータを先頭に。
  • -f segment -segment_format mpegts これはTSファイルにしている。
  • -segment_time 10 分割の時間を10秒程度にする。
  • -segment_list happy.m3u8 セグメントの分割されたファイル一覧(プレイリスト)
  • happy_%04d.ts 出力されるファイル名。 %04d が連番の形式

再生する方法

iOS 機器で、 m3u8 のファイルを開けばイイ。

HTMLに書くなら、

<video src="path/to/name.m3u8"></video>

再生チェックはVLCSafari

VLCにURLを渡すと再生できる。但し、ローカルのm3u8 ははダメ。HTTP前提です。

後でサンプル書きますが、m3u8 の中身に相対パスが書かれているのです。

iOS/mac OSXのSafari は再生できますね。

Android 版のchrome も再生できますね。

入力に使える動画について

ffmpeg が対応している動画ならたいてい読み込める。

もちろんパイプで渡せる。

また、USBのカメラやfacetimeカメラを取得してWEBサーバーに配置することでライブストリーミングが可能になる。

recpt1 --b25 --strip --sid hd 22 300 - |  ffmpeg  -  

などとrecpt1 と組み合わせても強い。

あれ?もしかしてffserver なくても行けるんじゃ。これ強い。

m3u8 のファイルの中身

at a4c19beea7bfbd97e611917a9eef4f79.m3u8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:18
#EXTINF:10.810800,
a4c19beea7bfbd97e611917a9eef4f79.00000.ts
#EXTINF:15.315300,
a4c19beea7bfbd97e611917a9eef4f79.00001.ts
#EXTINF:5.271933,
a4c19beea7bfbd97e611917a9eef4f79.00002.ts
#EXTINF:16.683333,
a4c19beea7bfbd97e611917a9eef4f79.00003.ts
#EXTINF:7.073733,
(中略
a4c19beea7bfbd97e611917a9eef4f79.00269.ts
#EXT-X-ENDLIST

EXTINF はファイルに含まれる秒数かな?

HTTPヘッダ

拡張子がm3u8 なら問題ないんだけど。拡張子を変えても、ヘッダがアレばチャント認識できる。

AddType application/x-mpegURL .m3u8
AddType application/x-mpegURL .playlist
AddType video/MP2T .ts

たとえば、playlistという拡張子でも ストリーミングはできますね。

takuya@~/Desktop$ curl -I http://192.168.2.1/hls/test.playlist
HTTP/1.1 200 OK
Date: Tue, 05 Apr 2016 18:59:23 GMT
Server: Apache/2.2.22 (Debian) Pxxx
Last-Modified: Tue, 05 Apr 2016 17:27:01 GMT
ETag: "5d4014b-402a-xxxfc02737f84b"
Accept-Ranges: bytes
Content-Length: 16426
Content-Type: application/x-mpegurl

HLS でファイルを作るメリット

動画を変換中でも再生ができる。コレが一番のメリット。

HLSだとストリーミングっぽく、ファイル断片をクライアントが取りに来てくれるので、結構簡単にライブストリーミングが可能になる。

断片化ファイルが10秒なら、10秒視聴中に10秒転送すると途切れることなく視聴できる。

このことから、必要な回線速度(クライアント側)が非常に計算しやすい。

また、クライアント側の回線速度が計算できると同時視聴数を考慮してサーバー側の必要回線速度も計算しやすいね。

通信もHTTPなので扱いやすい!シーク時キャッシュさせやすいかも。*1

一度にmp4 を読み込まないので、LTE通信などには優しい。10分くらいを先読みで読みこむようだ。

シーク時に再度読み込みが発生するのは辛い。

PC/OSXChromeは非対応。 Android版は対応している。

お手軽で、良い世の中になったね。

ffmpeg を使えば、便利すぎて、考えることをやめてしまう。

参考資料

HTML5のvideoタグで利用するmp4の動画を作る時のTips - Qiita

追記

なんでこんなことが必要か?単純な説明では、ブラウザはRANGEリクエストで10バイト目から20バイト目をApacheにリクエストできるが、10秒目から20秒目をリクエスト出来ないから。そもそも10秒目が何バイト目に当たるかはわからないし。HTTPには秒数指定で転送するための定義がない。だから事前に秒数ごとにファイルを分割して保存したものを転送するか、アクトビラみたいにApache側に秒数指定を実装するかだ。

*1: リクエストログ調べたけどキャッシュしてないっぽい。