Upgrade to Pro — share decks privately, control downloads, hide ads and more …

WebCodecsでの困ったところとハマりどころ / WebCodecs stuck po...

y-i
January 14, 2021

WebCodecsでの困ったところとハマりどころ / WebCodecs stuck point examples

WebTransport & WebCodecs meetup vol.0 で話したWebCodecsを使って映像をエンコード/デコードする際にハマりそうなポイントについてのスライドです。
デモで用いたコード: https://github.com/y-i/webcodecs-stuck-point-example

y-i

January 14, 2021
Tweet

Other Decks in Programming

Transcript

  1. 自己紹介 • 名前: ◦ 池田裕介 • お仕事: ◦ SkyWayの開発運用 ◦

    WebTransportとWebCodecsで実装を試してみる (これ) ▪ QuicTransportだけのサンプル ◦ NTT Coding Challengeの運営(問題作成とか) ▪ NTTコミュニケーションズのアドベントカレンダーに 記事を書きました • https://qiita.com/y-i/items/4c9339985d49f22e6947 2
  2. WebCodecsとは • 今のところGoogleChromeでのみ使える ◦ --enable-blink-features=WebCodecsフラグが必要 • ブラウザが使えるEncoder/Decoderを使うことができる ◦ VideoEncoder/VideoDecoderとして存在 •

    エンコード前のフレームのデータと エンコードされたデータの両方を触ることができる • キーフレーム制御や再送制御や帯域制御を自分でできる(する必要がある) 3
  3. WebCodecsでのエンコード側のデータのフロー 4 1. カメラや画面共有から
 映像を取得
 2. 映像のtrackのみを取得
 3. trackからエンコード前の
 フレームを随時取得


    4. エンコードして
 フレームから
 エンコード後のチャンクの
 バイナリデータを取得
 ※ AudioEncoderは
 2020/12現在では未実装
 MediaStream VideoTrack VideoFrame Encoded VideoChunk getUserMedia /
 getDisplayMedia 
 など
 getVideoTracks
 VideoTrackReader
 VideoEncoder
 受信側へ

  4. WebCodecsでのデコード側のデータのフロー 5 MediaStream Canvas Element VideoFrame Encoded VideoChunk Video要素など
 captureStream


    createImageBitmap
 & drawImage
 VideoDecoder
 送信側から
 1. チャンクをデコードしてエン コード前の
 フレームを取得
 2. フレームのデータを
 画像データに変換
 3. 画像をcanvas要素に
 毎フレーム毎に描写
 4. canvas要素を
 キャプチャした動画を
 MediaStreamとして取得

  5. お品書き • VideoEncoder => VideoDecoderと通すと色味が変わる • 途中からデコードしようとすると失敗する • フレームが飛ぶとデコードに失敗する(旧) ◦

    M88だと失敗しません • バックグラウンドタブでの遅延 • サンプルコード: ◦ https://github.com/y-i/webcodecs-stuck-point-example 6
  6. 事象2: 途中からデコードしようとすると失敗 • VideoDecoderにいきなりtype:”delta”な チャンクを投げると失敗する ◦ 差分を最初に送ってもダメというのは 理解できる • 上記の現象によってデコーダがエラーを吐いてしまう

    • state=closedになってしまいそれ以降映像を受理できない ◦ Decoding error.というエラーを吐く(M88) ▪ 以前はエラー内容が nullだった(M87) • 受信側でデコーダに渡す前に 最初がキーフレームになるよう フレームを破棄する処理が必要 8
  7. 事象3: フレームが飛ぶとデコードに失敗 (旧) • あるチャンクが失われた場合、 その後のtype:”delta”なチャンクを受け取ると エラーを吐く ◦ 現在は映像が乱れるだけになった ◦

    以前はエラー内容が nullだった • type:”key”なチャンクを受け取ると その後は正常に処理が可能 • チャンクと一緒にチャンクの番号を渡し、 keyframeでないチャンクで 番号が前のチャンクから飛んでいたら フレームの破棄とkeyframe要求を行う処理が必要 9
  8. 事象4: バックグラウンドタブでの遅延 • バックグラウンドのタブでは setTimeout/setIntervalの間隔が1秒くらいまで延びる ◦ 参考(MDN) • デコーダをその中で呼んでいるとどんどん遅延が発生する •

    単にデコードを省略すると映像が乱れてしまうので駄目 • keyframeを頻繁に送ることで解消できる ◦ keyframeが来たらそれ以前のをすべてスキップするなど実装 ◦ 例えば1秒毎にkeyframeを送るとバックグラウンドではない時に 1秒以内にkeyframeが来る => 追いつくことが可能 ◦ keyframeの方がデータサイズは大きいので 実際の頻度はユースケース依存に 10
  9. まとめ • VP9はとりあえず避けておいた方が良さそう • デコーダ側ではkeyframeを受けたことがあるかどうかの フラグがどうしても必要そう ◦ 次がkeyframeでないといけない状態とおいても良い • フレームが飛ぶと映像が乱れてしまうため、

    チャンクのデータと一緒にチャンクのナンバリングを 渡しておくのが無難 ◦ チャンクのタイムスタンプからも推測できるが 多少間隔がぶれるので追加で渡しておくのが良さそう • バックグラウンドタブに行くことを想定する場合、 keyframeを頻繁に送ると回復しやすそう 12