Mirrativ Tech Blog

株式会社ミラティブの開発者(バックエンド,iOS,Android,Unity,機械学習,インフラ, etc.)によるブログです

Mirrativにおける低遅延配信への取り組みについて【開発中】

こんにちは ハタ です。
Mirrativで開発中の低遅延配信機能について、ある程度形がまとまってきて、開発段階から品質チェック段階になりましたのでちょっとだけどんな感じになるか紹介させていただきたいなと思います。

なお、今回紹介するのは開発中のものからピックアップさせていただくので
実際にサービスにリリースされるものとは異なりますのでご留意お願いします。

言葉の定義

まず先に、世の中には「低遅延」という言葉の意味が沢山あるのですが
僕らのいう「低遅延」配信とはざっくり一言でいうと

「配信中の画面がインターネットを超えて視聴画面に見えるようになるまでの早さが短いもの」
としています。
つまり配信画面に映ってるものが視聴端末にすぐ(1秒未満)に再生されるようにする事が目標となっています。

配信した時刻にどれだけ近いか、を示す言葉として低遅延と呼んでいます

まずはどんなものを作っているのか

開発段階のデモシーンを一部ご紹介

f:id:octu0:20190301164722g:plain
デモをスマホで撮影したため縦画面です(この手は赤川)

この映像は弊社の開発環境で、実際にインターネット経由でどの程度の遅延になるかをデモした時の映像です。
左側のAndroid端末でエモモが手を振っているのを右側のiPhone端末で視聴のデモとなっています。
(何度も言いますが開発中のデモとなっているため実際にリリースされるものとは異なることがあります)

低遅延配信を実現するために取り組んでいる事をいくつか紹介できたらいいなと思っています。

目標の設定

現行環境では配信の遅延が概ね 2000ms(2秒) 程度に収まるように実装してあるのですが、これをもっと短く出来ないかというのを松竹梅形式で検討しました。

    • 目標遅延時間:1300ms
    • 配信サーバ・視聴プレーヤの再実装(各レイヤでのバッファリングを最小化する)
    • 目標遅延時間:500ms+
    • 配信側の修正(配信の方法から変えてしまう)
    • 目標遅延時間:300ms - 500ms
    • 配信プロトコルの変更(配信・視聴どちらもライブラリの更新は必要)

突然目標遅延時間が出てきたのですが、
これは「推測するな、計測せよ」のポリシーに則り、どの部分で遅延が発生する要因となっているかを調査し、だいたいこのあたりを改善すればこれくらいになるのではないかなと目星をつけた数値です。

推測するな、計測せよ

「推測するな、計測せよ」は僕自身が自戒の意味も込めてよく使う言葉です
元ネタは Unix哲学 です、まずは計測するところから始めました。

まず、僕らの配信サーバの構成は Origin / Edge 構成と呼ばれる構成になっていて、
配信された映像は Origin サーバに届き、その後 Edge サーバへ送られ、配信データを視聴できるようになっています。

f:id:octu0:20190301210514p:plain
映像データの流れ

ここでOriginサーバ側に届いた映像をEdgeサーバを介さず直接レンダリングするようにして、どれくらいの遅延が発生しているのかを調べることにしました(サーバの構成を変える必要があるのかも含め調査)。

ちょうどいい画面のスクショがなかったため当時記録用に残していた画面からの抜粋になってしまうのですが レンダリングを行ってみたところ下記のようになりました

f:id:octu0:20190301205051p:plain
左が配信画面で右がレンダリングした画像

ここで分かったこととして、Edgeサーバを経由させない場合に 680ms ほどの遅延となっているようです。
また、この方式だと映像が安定するまでに時間を要するということもわかりました

f:id:octu0:20190301211544g:plain
録画用に記録ていた僕のコンソールの様子

コンソールの様子なので分かりづらいのですが、どうやら Edge サーバではこういった映像を安定させるために、ある程度のまとまったデータのバッファを持ってくれているようです。
Edge サーバは Origin サーバの offloading を行っているため、即座にEdgeサーバを無くすことは現実的ではないのですが、このバッファをある程度減らすことは有効そうだということがわかりました。

視聴画面起動までの時間を短くする

次に取り掛かったのは、配信プレーヤ側です
実際に 680ms 程度の遅延が実現できるのか を検証してみたのですが、どうやらそうもいきませんでした。

f:id:octu0:20190301215737g:plain
プロトタイプ開発中のPlaygroundの画面

こちらも開発中の画面からの抜粋で申し訳ないのですが、このPlaygroundで試した時に黒い画面が表示されるまでに時間がかかり、680msとは程遠い時間です。
映像が始まるまでの時刻が遅れている時点では、せっかく Edge サーバの遅延を取り除いてもここが遅いのはもったいないです。

どうして遅いのかを調べるためログを仕込みつつどこか探していたところ、どうやら下記のように(ざっくり)見つけることができました。

2018-27-11 21:52:35.055 [Debug] [Mirrativ] // SPS が届いた時刻
2018-27-11 21:52:35.056 [Debug] [Mirrativ] // VTDecompressionSession 待機
:
2018-27-11 21:52:37.041 [Debug] [Mirrativ] // VTDecompressionSession 待機
2018-27-11 21:52:37.095 [Debug] [Mirrativ] // ここで描画

H.264(AVC)における SPS / PPS については今回はいったん省略しますが、チューニングの余地がありそうでした
特に SPS / PPS と直近の IDR のフレームは一刻も早く プレーヤに届けてあげれば起動までの時間が短くなりそうです
簡易的なサーバ実装をし、Playground で実装してみると

f:id:octu0:20190301221112g:plain
簡易サーバを通した後のPlayground

このように起動が早くなることが確認できました。
ただ直前の IDR フレームも送ってしまっているため、よく見ると再生後時刻が飛んでいる事がわかります。

ここで分かったこととして、現在の Edgeサーバとはちょっと違った Edge サーバの実装が必要そうであるということ、映像の並びを正しくしないと映像が飛んでしまうということが分かりました。

低遅延サーバの実装へ

(低遅延サーバの詳細な実装についてはいつか書きたいと思いますが)既存の配信すべてを置き換えるのは非常に大変なので、既存の配信はそのままに、低遅延に特化させたサーバプロセス(ミドルウェア)を作成することにしました

f:id:octu0:20190302220322p:plain
Originサーバ内のプロセスの様子

これによって、Originサーバからは 1つのストリームから複数のストリーム(既存のストリームと低遅延用のストリーム)が出るようにしました
既存の配信データをそのまま使うことで、iOS/Androidのアプリの改修を極力減らしつつ低遅延配信を実現する事ができるようにするためです。

また、この低遅延サーバが行っていることは、大量の映像フレームをほとんどバッファせずに、なるべく早く映像フレームをプレーヤまで届けるように設計しています。
ちなみに実装は、最近僕がよく使う Go言語を使ってサーバ(ミドルウェア)の実装をしています。

せっかく低遅延サーバを作成したので、既存のプロトコルでは実現できなかった下記のようなものも実現できるようにプロトコルから再実装しました。

  • 映像・音声以外のデータも扱えるようにしたい(例えば APNG のような動く画像をストリームに混ぜたい)
  • AVC 以外の映像コーデックの切り替えをできるようにしたい(コンテナの切り替えが容易であるようにしたい)
  • エモモとリップシンクした情報も送りたい
  • チャットもストリームの一種とみなして扱えるようにしたい
  • なるべくシンプルなパケットにしたい

当初はデコーダに最適化したサーバ実装の予定でしたが、作っていくとやりたいことが沢山あったのでそれを実現できるようにするための実装としました

Mirrativ アプリへ実装

低遅延サーバの実装ができたので、iOS アプリへ低遅延配信のデータを受け取れるように実装しました。
プロトコルの定義や配信サーバの実装も僕が行ったので、iOSの実装(プレーヤとライブラリの実装)も一緒に僕が実装を作りました。

その結果、エミュレータでの実行ですが下記のような状態にまで持ってくる事ができました

f:id:octu0:20190301153804g:plain
少し分かりづらいですがタップしてから映像が再生されるまでの時間が短くなっています

上記の映像は配信一覧画面から視聴したい配信に入るときの動作を新実装と旧実装で比べてみたものです。 映像を何度も見比べていただくのも大変だと思いますので、フレームごとに並べてみました

f:id:octu0:20190301160554p:plain
細かすぎて伝わりづらいかも...。

どうでしょうか、映像フレームでいくと100フレームほど改善したようです。

この時点で当初目標としていた、梅プランと松プランが合わさったような実装が出来上がっていました。

実機での実行

実際問題として実機でも実現できるのか分からないので、実機での実行とエミュレータ上ではない現実のネットワークを通じて低遅延が実現できているのか試してみました

f:id:octu0:20190301234139g:plain
真ん中が低遅延での視聴です

無事に実機でも実現できていることがわかりました
実際にこの時点のデータを計測してみたところ下記のようになりました

f:id:octu0:20190301234416j:plain
一番左が配信・真ん中が低遅延視聴・右が既存の視聴

この時点で160ms ほどの遅延が実現できました。

映像品質の問題

映像の遅延が少なくなったと同時に他の問題も出てきました
それはちょっとしたネットワークの品質の変化が起きると映像も同時に悪くなる事や、フレームレートが揃わないときの映像品質の劣化です。

f:id:octu0:20190301235827g:plain
ネットワーク品質が劣化したときの瞬間

このようにカクつきや映像の乱れがよく発生するようになりました。
低遅延だけを実現することはそう難しくないのですが、低遅延によってこうした今まで目に見えてこなかったネットワークの品質の影響をもろに受けるということがよくわかりました。

f:id:octu0:20190302000243p:plain
僕のエモモがこんなにノイジーな映像になるなんて...。

現在は QA を交えて、品質の劣化が起きても映像に影響がでないようにチューニングを行っています。
チューニングを行っている中でここまでに紹介した遅延時間ではなくなるかとは思いますが、なるべく高品質な状態でお届けできるように鋭意開発中です!

f:id:mirrativ:20190302214619g:plain
QAさんが色んな端末で沢山テストしてくれて、日々レポート沢山上がってきてます...!

低遅延配信の実現へ向けて

以上が低遅延配信への取り組みについて紹介させていただきました
まだリリースもしていないのと、QAによる品質向上のためにまだ開発段階であるものの、「こんな事やってるよ」くらいに思っていただければ幸いです。

また、今回は取り組んでいる事の紹介で、細かなところが紹介できなかったので折を見て細かなところを紹介したいなと思っています

例えば

  • 実は大変、低遅延とバッファリングのせめぎ合い(ジャギる・カクつく・止まる)
  • ネットワークのjitter処理と映像の綺麗さの悩ましい関係(回線品質ディテクションの挑戦)
  • 可変ビットレートと可変フレームレートと低遅延の実現の難しさ
  • (今回省略した内容)
  • (そもそもの低遅延サーバの実装)

などなど、QAを通して分かったことや品質を上げるために苦労したところなど、いつか書きたいなと思います。


We are hiring!
低遅延配信を一緒に開発してくれるエンジニアを募集中です! 体験入社というのもあるのでお気軽にどうぞ!

www.mirrativ.co.jp