🧊

MediaStreamをMediaRecorderでWebMにして定期的にサーバーに送ってMPEG-TSにして最終的にHLSで配信する

っていう実験を弊社の開発合宿でやったので、その学びをメモっておきます。

最近こういうわかりやすいようでわからないタイトルの記事が多い気がする・・。

構想

  • `getUserMedia()`でローカルストリームをとってもいいし
  • WebRTCでつないでリモートストリームをとってもいいし
  • なんしかMediaStreamをMediaRecorderでWebMにして
  • 定期的にサーバーに送ってその都度MPEG-TSに変換
  • 最後にHLSの`.m3u8`を手書きして配信

過去に似たようなことをやってる人は既にいたので、若干のネタ被り感はある。

Inspired by

GitHub - JosePedroDias/webcam2hls: serve your webcam via the MediaStream Recording API on the browser, will send webm videos to the server which will generate HLS stream for playback

2014年の作品。

  • WebMを一括でサーバーに送って変換するタイプ

単純に`ffmpeg`で変換すればいいのはわかってたけど、それだと長時間録画で死ぬ気がしたのでそこが差異。
あと内容が古いからか動かなかった・・。

MediaRecorder と WebM で、オレオレ Live Streaming

2015年のがねこさんの作品。

MediaRecorderの辛さはここで先に知ってたけど、2017年になってるし何か変わってるかも・・?という期待もあった。

いくつかのパターンが試行されてて、

  • WebMをWebMのまま定期的に再生するタイプ
  • WebMをサーバーで単一ストリームにためて、それを返すタイプ

ただ前者はフォーマット的な問題があるし、後者はいつまでもレスポンスが返ってこないことになるので微妙だなーと。

というわけで、今回の構想は中々いいラインを攻めてるのではないかなーと思ってた。

結果

github.com

成功といえば成功、失敗といえば失敗かなーという感じ。

セグメントを適切な長さで送ってるので、クライアント・サーバーともに処理の負荷は大したことないし、通信量も抑えられてるので、長時間の録画にも向いてる。
試しに録画した分だと45分は撮れてたし、理論上はもっと長くても問題ないはず。

リモートのストリームも問題なく録画できるので、出先とかイベントで「iPhoneからざっくり撮ったものを、後から見返したい」っていう当初の目標は達成できた。
ただひとつ失敗かなーと思うのは、最終的な成果物であるHLS形式のアセット一式が、Safariでしか再生できなかったこと。

HLS.jsを通すと最初のセグメントしか再生されず、動画の合計時間も上手く取得できないような挙動に・・なんでやろう・・。
HLS.jsがエラーを吐くわけでもないので、メディア側の問題なんやろーとは思うけど、Safariで再生できるからなーなんでやろう・・。

`.m3u8`の記述には問題ないはず・・なので、MPEG-TSのトランスコード(`ffmpeg`の設定)で何か足りなかったんだろうか・・。

ちなみに、単一の`.webm`を`ffmpeg`でセグメントに一括分割するパターンだと上手く再生されるので、やっぱりトランスコードまわりかなー。

学び

合宿で発表した資料があるのでそちら参照です。

MediaStream to HttpLiveStreaming

3行でまとめると、

って感じでした。