📝 この記事は forge.workstyle.tech に掲載した記事の転載です。
Electron製アプリをMacで配信中、利用者がリモートデスクトップから端末を操作できなくなりました。psでは配信用ウィンドウが492%、ffmpegは28%で、録画側が重い状態でした。録画サイズが指定されずRetinaの実解像度で録画していたことと、MediaRecorderとffmpegで二重に符号化していたことが原因でした。
原因は録画サイズと二重符号化
原因は二つありました。
一つ目は、画面録画のサイズを指定していなかったことです。コードはgetDisplayMedia({ video: true })でした。設定画面には1280×720、30fpsと表示していましたが、その値は録画に反映されていませんでした。
指定がないまま、Retinaの実解像度で録画していました。画面は3456×2234などの大きさです。設定値を見て配信負荷を見積もっていた私には、ここが盲点でした。録画は小さなウィンドウのつもりでも、実際には大きな画面を取り込んでいたのです。
二つ目は、映像を二度符号化していたことです。MediaRecorderがVP8をCPUで符号化し、その映像をffmpegがH.264に変換していました。端末の符号化器VideoToolboxが使われるのはffmpeg側だけです。録画側のVP8符号化はCPUに残ったままでした。
配信の前段である録画にも、符号化の仕事があります。プロセスを分けて測ったことで、負荷の場所が分かりました。
録画形式を先に決める
修正では、まずgetDisplayMediaにmaxつきで大きさとフレームレートを渡しました。これで録画側に上限を伝えます。
次に、MediaRecorderではH.264を先に試すようにしました。端末の符号化器が使える形式で録れれば、ffmpegに映像を作り直させずに済みます。実際に録れた形式はvideo/mp4;codecs=avc1,mp4a.40.2でした。
その場合、ffmpegは-c:v copyで詰め替えるだけにします。ここで-b:vや-rを指定すると、映像を結局作り直すことになります。コピーするなら、余計な指定は足しません。
ただし、MediaRecorderがどの形式で録れるかはウィンドウ側でないと分かりません。そこで、ウィンドウから形式の知らせを受けてからffmpegを立ち上げるようにしました。
順番を変えるときは、先に止められる理由を調べます。ffmpegが無い、鍵が無い、といった状態なら、ウィンドウを開く前に利用者へ伝えられます。ウィンドウを先に開いてから「送れません」と表示すると、利用者からは配信中に見えてしまいます。
録画側は約30分の1に
修正後、同じMacで20秒ごとに4回測りました。録画側のCPU使用率は14.8%、16.3%、19.6%、19.2%。ffmpegは0.1%でした。load averageは3.28、3.48、3.27、4.16です。
録画側の負荷は約30分の1になりました。load averageの3〜4には、LLMや埋め込みなどアプリ本体の負荷も含まれています。配信そのものの負荷は、ほぼ無視できる程度です。
ひとつ断っておきます。修正後の回は、受け皿の配信枠を終えた後だったため、YouTubeへの到達を再確認していません。到達を確認できたのは修正前の回です。そのときは9分半配信し、画質は「非常に良い」、ビットレートは3064 kbpsでした。修正後の負荷が下がったことと、修正後の配信到達を確認したことは別です。
負荷が高すぎたら、アプリが自動で配信を止める
負荷を下げても、運用上の不安は残ります。今回いちばん重かったのは、利用者が配信を止められなくなったことです。私は別の経路から止められましたが、利用者には同じ手段がありません。
そこで、負荷が高いときはアプリ自身が配信をやめる仕組みを入れました。配信中は1分平均の負荷を10秒ごとに見ます。負荷がCPUの数 × 2.5を超えた状態が3回(約30秒)続いたら、アプリが自動で配信を止めます。
一瞬だけ跳ね上がったときには止めません。一度でも落ち着いたら、回数を数え直します。やめるときは理由と直し方も画面に出します。たとえば、録画する大きさを下げるよう案内します。
利用者が操作できないほど重くなってから、利用者に停止を求めても遅いのです。異常を検知して止まるところまでを、配信機能の設計に含める必要があります。
まとめ
-
getDisplayMediaにサイズとフレームレートをmaxつきで指定する - MediaRecorderが実際に出力した形式を確認してからffmpegを起動する
- コピーできる形式ならffmpegは
-c:v copyで詰め替え、映像を作り直す指定を足さない - 配信中は負荷を監視し、高負荷が続いたらアプリが自動で配信を止める
関連記事
- https://forge.workstyle.tech/blog/av-sync-and-mediarecorder-pitfalls/
- https://forge.workstyle.tech/blog/automate-youtube-twitch-live-streaming/
- https://forge.workstyle.tech/blog/headless-chromium-real-gpu-rendering/