本セッションの登壇者
セッション動画
僕の方からは「Media Over QUIC 最新事情」という話をしたいと思います。Media Over QUICは映像通信向けQUICの規格で、IETFから出て1年ちょっとぐらいです。自己紹介は割愛します。
今日の概要ですが、Media Over QUIC(MoQ)について、従来の映像通信であるHLSやWebRTCと何が違うのかという話と、標準化の最新動向の話をします。
![](https://res.cloudinary.com/techfeed/image/upload/v1717667808/entries/abuwivtlqipln6ggf5ok.png)
既存方式の短所を埋めるMedia Over QUIC
まず、Media Over QUICとは何かという話ですが、Web上では2つの方式が使われています。1つはHLSやMPEG-DASHなど、メディアをHTTPで送る方式で、今ご覧いただいているYouTube Liveもまさにこの方式です。柔軟でよくできているプロトコルではあるんですが、遅延が大きいという問題点があります。もう1つはWebRTCで、会議や会話で使えるぐらい遅延が小さいですが、あまりカスタマイズできません。
![](https://res.cloudinary.com/techfeed/image/upload/v1717667828/entries/bit6qvxysnizggqn0zib.png)
これらに対してMedia Over QUICは、遅延も小さいし、面白い映像サービスも作れるというものです。
![](https://res.cloudinary.com/techfeed/image/upload/v1717667865/entries/ierkbohbvsaukxx6m4us.png)
簡単なデモをご紹介します。
![](https://res.cloudinary.com/techfeed/image/upload/v1717667873/entries/ruehee8mqfelbwreob15.png)
Media Over QUICを使って作った簡単なサンプルデモです。左側はブラウザで、今カメラで撮った映像を送信しているところです。それをMedia Over QUICを使ってAWSの東京リージョンに置いたリレーサーバに飛ばして、右側で受け取って表示しています。今、6 msぐらいの遅延になるように設定していて、WebRTCではこれくらい遅れて表示されます。
![](https://res.cloudinary.com/techfeed/image/upload/v1717667881/entries/xm31dm4jhvaispn0wqfy.png)
Media Over QUICを使うと遅延を設定できるので、こんな感じで遅延がまったく起きないような通信サービスができます。
![](https://res.cloudinary.com/techfeed/image/upload/v1717667888/entries/dapigpcdw3r7xtfviiah.png)
そもそもQUICとは?
Media Over QUICの背景として、まずQUICの話をします。突然ですが、QUICは僕から見るとドローンみたいなものだと思っています。
![](https://res.cloudinary.com/techfeed/image/upload/v1717667894/entries/pd1pbfyvd0octgji08gg.png)
どういうことかと言うと、これはHTTP/2の場合の絵ですが、TCPを道路だとすると、リクエストがそれぞれトラックで運ばれるモデルになります。何もなければよいのですが、パケットロスが発生するなど、先頭車両で事故が起きると、後ろの車両がそこで何もできなくなります。
![](https://res.cloudinary.com/techfeed/image/upload/v1717667899/entries/o72thk0afs65phi0ng3o.png)
これをHead of Line Blockingと言います。これがQUICだと解決されています。
![](https://res.cloudinary.com/techfeed/image/upload/v1717667904/entries/po7yyfd9pnfpxaj7hx4c.png)
QUICも1つの道路ですが、リクエストはドローンで運ぶような感じになります。
![](https://res.cloudinary.com/techfeed/image/upload/v1717667910/entries/fsce5bnb6l4e13oqb3om.png)
先頭のドローンに問題が起こっても、後ろのドローンが空中を飛んでいるので大丈夫です。
![](https://res.cloudinary.com/techfeed/image/upload/v1717667915/entries/llyyrclbatprgqwuhwbx.png)
なので、QUICはUDPを利用しています。とてもざっくりした説明ですが、イメージをつかむための喩えです。
![](https://res.cloudinary.com/techfeed/image/upload/v1717667921/entries/zxvx6elhiqwmmfqzrq35.png)
HLS、MPEG-DASHよりもジッター吸収が効率的に
HLS、MPEG-DASHの話も少しします。これらはメディア版のHTTPですが、仕組みはエンコーダからの映像を一度セグメントファイルとして分割してWebサーバに入れて、それを順々にダウンロードしたものをプレーヤーで処理してライブストリームを表示するものです。
![](https://res.cloudinary.com/techfeed/image/upload/v1717667930/entries/w8ba392egw9lqhg0cux2.png)
HLSやMPEG-DASHは遅延が結構大きいですが、その理由は、受信したセグメントファイルを受信バッファ、一般的にはジッターバッファと呼びますが、これに少なくとも2、3個入れて到達揺らぎを吸収する必要があるため、貯める分だけ遅延ができるからです。
![](https://res.cloudinary.com/techfeed/image/upload/v1717667956/entries/ba2lhutpp0m5quruvzm8.png)
映像というのは1系列でGroup Of Pictures(GOP)という、最初にIフレームというJPEGのような画像フレームが来て、その後に差分フレームが続きます。それによって圧縮率を高める仕組みです。なので、映像を取り扱う時には必ずIフレームとBフレーム、Pフレームのすべてが必要で、差分データだけ送られても映像を復元できません。
![](https://res.cloudinary.com/techfeed/image/upload/v1717667963/entries/bnoy3ldnws57kqxibkpv.png)
HLSやMPEG-DASHは基本的にはこのGOPのデータを1つのセグメントにして、一般的には15秒ぐらい送り付けます。Low Latency HLSでは、2秒分ぐらいのデータで扱いますが、どうしても遅延が4~6秒程度になります。
![](https://res.cloudinary.com/techfeed/image/upload/v1717667969/entries/qmjpos2o31tzerczztrj.png)
これが、フレーム単位で送れるようになったのが、Media Over QUICの特徴です。これができる理由は、ストリームを別々に割り振って送ることができるからです。Head of Lineのブロッキングがなくなったので、Media Over QUICではフレーム単位で映像を送れるようになりました。
![](https://res.cloudinary.com/techfeed/image/upload/v1717667974/entries/ody2yeptoaf1nkgsjbsm.png)
Media Over QUICについてはメタのオープンソースでリポジトリが出ています。WebCodecsを使って、エンコードデータのフレームを1つ作るたびにこのコードがコールされます。uniStream
(Unidirectional Stream)という変数を作成して、そこに書き込んで送信した後にそれをクローズする処理をしています。
![](https://res.cloudinary.com/techfeed/image/upload/v1717667980/entries/qcosyexj7yitu0fsyo7l.png)
Media Over QUICで低遅延化ができる理由は、デモでもお見せしたように、30 フレーム/秒の映像であれば33 ms。それを2、3個溜めればよいためです。
![](https://res.cloudinary.com/techfeed/image/upload/v1717667985/entries/kfflhuvenmmhkzaoiiqm.png)
ネットワーク環境に依存しますが、バッファ遅延を100 ms入れればOKです。映像をフレーム単位で扱えるというのがポイントです。
![](https://res.cloudinary.com/techfeed/image/upload/v1717667990/entries/j5ofupifbprenlla6d1z.png)
映像通信アプリでできたことがWebでもできる
次にMedia Over QUICの実装パターンです。ブラウザで実装する際のパターンですが、送信側はみんな大好きgetUserMedia()
で映像を取得したら、フレーム生成して画像を取って、WebCodecsに入れるとエンコードしてくれます。その後、送信するためにRTP相当のLOCというフォーマットでパケッタイズして、MOQTでトランスポートプロトコルでくるんで、WebTransportでQUIC送信します。
![](https://res.cloudinary.com/techfeed/image/upload/v1717668000/entries/xrluchov0lxkzxg6tttl.png)
受信側は、WebTransportで送られてきたデータをMOQT Subscribeで受け取って、データを取り出したら、先ほどのジッターバッファに入ります。その後、requestAnimationFrame
などのきれいなクロックで取り出して、LOCを外して、デコーダーに入れて、レンダリングして終わりです。ここで、赤で示しているジッターバッファが、WebRTCにはない仕組みです。ここを調整することでいろいろな映像アプリを作れるというところが1つの面白さだと思います。
![](https://res.cloudinary.com/techfeed/image/upload/v1717668008/entries/dq5wn4jzjlvdp0uygsty.png)
低遅延の話ですが、このジッターバッファのバッファサイズを変更すると、低遅延から高遅延まで簡単に変えられます。たとえばネットワーク環境に応じて、ジッターが小さければここを小さくする、不安定なところでは画像が乱れるのである程度ジッターバッファを取る、という形です。
![](https://res.cloudinary.com/techfeed/image/upload/v1717668014/entries/l8y0kbbgw0i2j8esvyl5.png)
今日はお見せできなかったのですが、もう1つのデモとして、送信側からMIDIの鍵盤のデータを送って、受信したタイミングで鳴らすものがあります。映像とデバイスデータとの同期みたいなもので、映像は先ほどの説明と同じですが、デコード側のWebCodecsで、画像データが変わった瞬間にタイムスタンプを取り出すことができます。つまり、キーボードを押した時に、そのタイムスタンプに近いところが取得できるんです。それをキャプチャ時のフックとして入れて、MIDIデータを別のバッファに入れて、フックで音源を再生することで、映像と同期して音を鳴らすことができます。
![](https://res.cloudinary.com/techfeed/image/upload/v1717668022/entries/pyags2x6arv5wzt2yutp.png)
今の説明は、ネイティブ映像通信アプリを書いていた人にとっては当たり前の世界だったんですけれども、Webではできなかったんですね。これが普通にWebでもできるようになったのが面白いなと思っています。個人的にはこれこそWeb 3.0なのではないかと思っています。あくまで私見です。
![](https://res.cloudinary.com/techfeed/image/upload/v1717668030/entries/yshbcwcc3ndeqza4rwqh.png)
ネイティブアプリケーションの世界だと当たり前ですが、Webではできていなかったことができるようになるということです。フレーム単位の制御や同期ができるというのは、1つの大きな特徴だと思います。
![](https://res.cloudinary.com/techfeed/image/upload/v1717668037/entries/knjnworxiyhhcfcbb2wn.png)
ブラウザのサポート状況ですが、WebCodecsに関してはFirefoxはちょっと残念な感じで、Safariが画像だけはOK、音声は対応していません。
![](https://res.cloudinary.com/techfeed/image/upload/v1717668045/entries/roypqghjzljjuutunezl.png)
ただ、Audioコーデックにはwasmを使うなどいろいろなやり方があるので、何とかなるかなとは思っています。
![](https://res.cloudinary.com/techfeed/image/upload/v1717668052/entries/mv4nebku3o59eje1e7de.png)
次はWebTransportで、これはSafariだけがまだサポートしていない状況です。
![](https://res.cloudinary.com/techfeed/image/upload/v1717668058/entries/trx1f4agqzkfxd5gp7uf.png)
ただ、2023年4月ぐらいからWebKitのStandards PositionsにWebTransportがサポートされていて、実際にWeb上での実装も始まっているので、もうしばらく待とうかなという感じです。
![](https://res.cloudinary.com/techfeed/image/upload/v1717668064/entries/osydrbuw40pschgnzjun.png)
![](https://res.cloudinary.com/techfeed/image/upload/v1717668073/entries/dsdf4b7nt9ajcx75uebu.png)
プロトコルの詳細を議論中
少しだけプロトコルの話です。プロトコルスタックの典型的なケースはこんな感じです。メディアデータをやり取りする時はLOCパッケージでくるんで、MOQTのポートに入れて、ブラウザならWebTransport経由でQUICに入れる、ネイティブアプリケーションならそのままQUICに入れます。たとえばMIDIデバイスの操作データなどのarbitary dataは直接MOQTに入れます。その他、番組情報のようなものをやり取りするためのカタログという概念があります。このようなプロトコルスタックになっていて、MOQTとLOCとcommon catalog format、WebTransportが今、IETFで議論されています。
![](https://res.cloudinary.com/techfeed/image/upload/v1717668081/entries/zpcffzg2pjdvtfqr4fqw.png)
MOQTのシーケンスチャートです。送り側と受け側がMOQT relayにSETUPを送信します。Pub-Subモデルになっていて、送信側がPublish
と同等のAnnounce
をrelayに送信します。レシーバーがそれに対してSubscribe
メッセージを送ると、中継されて送信側に伝達され、認証チェックを行います。認証がOKになると、映像ストリームデータなどの送信データがどんどん送られます。これがMOQTです。
![](https://res.cloudinary.com/techfeed/image/upload/v1717668087/entries/bqqiujsczaddoljchugu.png)
MOQTの中のデータ構造です。ネスト構造ですが、時間の関係で割愛します。
![](https://res.cloudinary.com/techfeed/image/upload/v1717668156/entries/tb1mfr7lqi8p4upwtlmq.png)
最後に、METAからリポジトリでリファレンス実装が出ています。他にもいろいろ出てきているので、チェックしてみてください。僕からは以上になります。
![](https://res.cloudinary.com/techfeed/image/upload/v1717668099/entries/x6ah2jympo3mevmzbj5l.png)