塩焼きブログ

塩焼きに関しての研究内容を公開しています

MP4ファイルを分割してHTTP Live Streamingでストリーミング再生を行う

HTTP Live Streaming(HLS)でストリーミングを送る方法についてまとめます。外部サーバーを利用せずに自前のサーバーから動画配信をすることができます。共用サーバーでも動作しそうですが試してません。

ffmpegのインストール

ここによるとbrewでインストールする時にAACを含められるようなので再インストールしました。フルカスタムMacbook Proで10分かかった。しかし実際はどうなのだろうか。継続的なエンコード処理についてはLinux上から行うからMac上でのffmpegについては深掘りするのはやめておきます。

breq uninstall ffmpeg
brew install --use-clang --HEAD ffmpeg --with-faac --with-fdk-aac --with-ffplay --with-fontconfig --with-freetype --with-frei0r --with-libass --with-libbluray --with-libcaca --with-libquvi --with-libsoxr --with-libvidstab --with-libvorbis --with-libvpx --with-opencore-amr --with-openjpeg --with-openssl --with-opus --with-rtmpdump --with-speex --with-theora --with-tools --with-x265 --enable-libx264 --enable-gpl --enable-libxvid --enable-shared

mp4ファイルのtsファイルへの変換

次に変換ですが、まずは対象ファイルがオーディオコーデックを調べます。

ffmpeg -i file.mp4

今回のmp4のファイルはaacであることがわかったので、次にここを参考にストリーミング用ファイルに変換を行います。こちらもほぼコピペです。

ffmpeg \
  -i ./file.mp4 \
  -vcodec libx264 \
  -movflags faststart \
  -vprofile baseline -level 3.0 \
  -g 150 \
  -b:v 519k \
  -s 768x432 \
  -acodec aac \
  -b:a 63.4k \
  -ar 44100 \
  -flags +loop-global_header \
  -map 0 \
  -f segment \
  -segment_format mpegts \
  -segment_time 5 \
  -segment_list ~/hoge/files/playlist.m3u8 \
  ~/hoge/files/v%03d.ts

変換には多少時間がかかります。

ストリーミング再生を行う

先程変換したファイルを下記のような構造に配置します。この時playlist.m3u8内のパスも合わせてください。さっきのコマンドで実行していればパスは問題なく設定されているんじゃないかと思います。

├── files
│   ├── playlist.m3u8
│   ├── v000.ts
│   └── v001.ts
└── index.html

そしてindex.htmlではこちらを参考に下記のような記述をします。これもほとんどコピペです。

<!DOCTYPE html>
<html lang="ja">
<head>
  <title>HLS</title>
  <script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
</head>
<body>
<video id="video"></video>
<script>
  if(Hls.isSupported()) {
    var video = document.getElementById('video');
    var hls = new Hls();
    hls.loadSource('./files/playlist.m3u8');
    hls.attachMedia(video);
    hls.on(Hls.Events.MANIFEST_PARSED,function() {
      video.play();
    });
  }
</script>
</body>
</html>

最後に適当にサーバーを立ち上げてindex.htmlにアクセスします。PHPのビルトインサーバーでいいんじゃないでしょうか。

php -S localhost:8080 -t ./

メモ

ネイティブで対応しているSafariやiOSについて

SafariやiOSはネイティブで対応しているので分岐処理によって、ネイティブの方法で実装を行うと良い。hlsjsでできることは大抵HTML5のvideo要素のイベントで対応することができる。プリロード周りの正確な処理についてはhls.jsでなければできないこともあるが、そこまで厳格な処理をすることはあまり無いのでHTML5のネイティブの実装で問題ない。

ffmpegでの分割ファイルのサイズについて

ビットレートと分割時間を調整することで適切なサイズに抑えるようにする必要がある。あまりビットレートを大きくしたり、分割時間を大きくすると1ファイルあたりのダウンロードに時間がかかり、配信サーバーに無駄な転送量を強いることになるので、おすすめとしては分割時間は短めにして、プリロードを事前にさせないようにするのが良い。

通信速度の悪い環境での対応について

video要素には様々なイベントが用意されており、中でもwaitingというイベントを利用することでリソースの取得に時間がかかっているということがわかる。waitingが発生したら読み込み中の画像を出して、再開するとplayingイベントが呼ばれるので読み込み中画像を削除することで、より良いプレイヤーが作れると思います。

HTML5のみの実装について

こちらの方法でHTML5を利用してできるような感じなんですが、今のところ動くのはSafariだけなんですよね。クロスブラウザ対応になるとライブラリが必要。