虎の穴ラボ技術ブログ

虎の穴ラボ株式会社所属のエンジニアが書く技術ブログです

MENU

外で限りなく安定配信を目指してみた

この記事は虎の穴ラボ Advent Calendar 2024の4日目の記事です。

こんにちわ、虎の穴ラボのH.Y.です。
今回は、個人的な趣味で安定した外配信を目指してみたという話です。

きっかけ

自分は、配信するのも趣味ですが、ふとドライブの外配信をしてみたいなと思い
試しに、スマホでドライブ配信をしてみて接続がブチブチ切れるのでこれをどうにかしたいというのがきっかけでした。

外配信での問題点

自分は配信にTwitchを使っているのですが、
そこでは配信プロトコルにRTMP、映像コーデックにはH.264(AVC)が使われています。

RTMPの問題

自宅で光回線を使って配信をする分には全く問題ないのですが、RTMPは映像と音声を別々で送る仕組み上、
通信が不安定な場合、音ズレが起きてしまいます。
またTCPなのでパケットが壊れると、再送などが生じ遅延が多くなります。

H.264(AVC)の問題

配信で必要なTwitch推奨の上り帯域は以下のとおりです。

解像度 フレームレート (fps) 映像ビットレート (kbps) 音声ビットレート (kbps)
1080p 60 4500~6000 160
1080p 30 3500〜5000 160
720p 60 3500〜5000 160
720p 30 2500〜4000 160

1080pの解像度の場合、5~6Mbpsのビットレートが推奨になりますが、
これは5~6Mbps上り帯域が常に必要という意味になります。
ただ、この5~6Mbps上り帯域は4Gのモバイル通信の場合、
静止状態でも6~10Mbpsの場合が多く、ギリギリになります。
なので、ちょっとでも電波が悪いと配信が途切れたりします。

外配信の最適な構成案

RTMP→SRTに変更

SRTはRTMPと違いUDPベースの配信プロトコルです。パケットが壊れた場合、
エラー訂正能力で修復できるので、再送が少なく遅延が少なくなるという特徴があります。
また、映像と音声をタイムスタンプをつけて同期して送信しているので、音ズレは起きにくい仕組みになっています。

H.264(AVC)→H.265(HEVC)やAV1に変更

H.264(AVC)で6Mbpsの場合、H.265(HEVC)やAV1に変更すると同じ画質で半分の3Mbpsで済みます。
H.265(HEVC)よりAV1の方がより低いビットレートで済みますが、
機材の関係でH.265(HEVC)のハードウェアエンコードしかできないので、今回は、H.265(HEVC)を使用します。
ちなみに、次世代のコーデックであるH.266(VCC)の場合は、1.5Mbpsになるらしいです。

変換サーバの構築

SRT-H.265(HEVC)の構成でそのままTwitchに送ることができれば問題ないのですが、
Twitchが対応していないので、途中でRTMP-H.264(AVC)に変換する必要があります。

通信が不安定そうなモバイル通信部分はSRT-H.265(HEVC)で通信を行い、
通信が安定してそうな部分はRTMP-H.264(AVC)を使う構成にしました。

変換サーバはさくらクラウドの10コアサーバを使用しました。(8コア以上でないと遅延しました。)
サーバにFFmpegを実行できる状態で下のようなシェルを実行しておきます。

#!/bin/bash
while true
do
    ffmpeg -i srt://{{このサーバーのグローバルIP}}:9888?mode=listener  -c:v libx264 -preset fast -b:v 6000k -maxrate 6000k -bufsize 12000k -c:a aac -b:a 160k -f flv rtmp://live.twitch.tv/app/{{twitchのプライマリストリームキー}} >> /var/log/stream.log 2>&1
    echo "FFmpeg crashed on $(date) -- restarting" >> /var/log/stream.log 2>&1
    sleep 1
done

-c:v libx264は動画コーデックH.264(AVC)
-b:v 6000k -maxrate 6000kは映像ビットレート6Mbps
-bufsize 12000kはバッファーサイズを12MB
-c:a aac -b:a 160kは音声コーデックACCで160kbps
という設定になっています。

映像、音声のビットレートに関しては、Twitchの推奨ビットレートにしています。
バッファーサイズは大きければ大きいほど安定した通信になるのですが、
大きすぎると遅延がどんどん大きくなってしまうという問題が発生するので2秒ぐらいのバッファーである12MBにしています。

通信が不安定になるとプロセスが終了するので、1秒後に再実行するようにシェルで動かしていました。
H.265(HEVC)→H.264(AVC)の変換には、かなりのCPUリソースを使用します。
そのため、さくらクラウドの10コアサーバを利用してトランスコーディングをしました。
ちなみに、自宅サーバなどを利用するのであれば、
大抵ハードウェアエンコーダーが使用できるので、もう少し少ないCPUコアで実現できると思います。

OBS Studioの設定

ストリーミング配信を行うソフトウェアとしては、
一般的に利用されているOBS Studio(以下OBS)を利用することとしました。
SRTで送出する映像情報は自前の変換サーバを経由してTwitchへ送るため、
OBSの配信先はカスタムサーバとし以下のような設定をしています。

srt://{変換サーバのIP}:9888?mode=caller&latency=2000

modeは送受信を設定するオプションです。callerにすると送信設定になります。
latency=2000は配信のバッファーが2000msという意味です。
先ほど作成した変換サーバを配信先として指定します。
動画コーデックはH.265(HEVC)、ビットレートはCBRの3.0Mbpsで設定しています。

ボンディング

OpenMPTCProuterを試してみるが・・・


以前にOpenMPTCProuterを使ってボンディングルータを作り分散通信を試したことがあります。

ボンディングルータを作って、外で限りなく安定通信を目指してみた - 虎の穴ラボ技術ブログ

この時のシステムを使って安定配信をしようとしましたが、
OpenMPTCPRrouterにはUDPの分散ができない不具合があるとのこと。

・SRTが分散せずに偏るというissue
SRT stream not working · Issue #3227 · Ysurac/openmptcprouter · GitHub
・SRTでglorytun UDP(UDPのVPN)を使っても不安定というissue
Aggregation glorytun UDP doesn't work for me.. · Issue #3363 · Ysurac/openmptcprouter · GitHub

これでは、ボンディングが使えないので別の方法を探しました。

別のボンディングを試す

有料にはなりますが、個人向けのボンディングサービスを提供している会社もあります。

Speedify - Use all of your Internet connections at the same time

月額1645円程度必要(年契約ならもっと安くなります)になりますが、UDPのボンディングもいけそうです。

一旦配信してみる

ここまで紹介した方法を利用して配信をしてみます。

配信の条件として以下の状況で配信しました。
回線5回線
- docomo(mineo)
- docomo
- au(mineo)
- Rakuten
- Softbank(mineo)

配信日時
- 2024年07月07日15時ごろ

配信場所
- 国道129号線のららぽーと湘南平塚から西湘バイパスを行きながら配信

ブロックノイズが写っている時間の割合は5%程度でしたが、
電波が悪いところ(アンダーパスや海沿い)だと明らかにブロックノイズが多くなっているのがわかります。
これを検証するため、電波が悪そうな海沿いの西湘PA下り(西湘バイパス)で静止状態で配信しました。

youtu.be

結果は以下のようになりました。

条件 ブロックノイズ発生率
通常道路 5%
アンダーパスや海沿い(電波状況が悪い箇所) 38%

電波が悪いところでも安定して配信したかったのですが、
ボンディングをしている効果があんまり感じることができませんでした。

失敗した理由を考える

電波状況の悪い箇所でブロックノイズの発生が多くなる原因を考えてみました。

UDPボンディングによりパケットの順序がバラバラになったのではないかという線で予想しました。
Speedifyには冗長モードと分散モードというボンディングのモードがあります。
冗長モードは、同じ通信内容を全部の回線に送り、最速で届いたものを採用するモードで、
分散モードは文字通り各回線に分散して送るモードになります。

通信を行いながら移動を行っている場合、大抵の場合冗長モードが自動的にONになってしまいます。
今回は1回線あたりの帯域使用を減らしたかったこともあり、分散モードを利用する設定にしていました。
通信を安定させるために行った設定でしたが、結果としてこの設定によって配信が不安定になったと考えました。

さらに外配信に強いプロトコル

ボンディングを使って配信・放送を行う業務用機器が業務用で販売、レンタルされていますが、
それらの機器はどう言ったシステムが使われているかを調査しました。

この3社の共通点といえば、ボンディングに特化しているプロトコルを使用しており、
これらはすべてオープンなプロトコルではないということです。

個人で使える外配信に強いプロトコル

業務用の機器を使うのはコスト的に現実的ではないので、個人でも使用できるプロトコルを探しました。
いろいろ探したところ、RISTというストリーミングプロトコルを見つけました。

IP圧縮規格RISTとは - Cobalt Digital - 放送・映像関連製品 | 伊藤忠ケーブルシステム株式会社

今回利用したSRTのパケットロス耐性が12~15%に対し、RISTは40~55%とかなり高いです。
ただ、RISTには再送機能がないので、エラー訂正能力に偏らせているような感じです。

デメリットといえば、知名度が低いので、日本語の文献がほぼないのと、
探した限りではスマホ用アプリが存在しなかったりします。
エラー耐性が高い分パリティをのせているので通常の配信に比べて1.5倍の通信量になります。

しかし、現在使っている配信ソフトのOBS、配信サーバに送るために変換するffmpegでも対応しており、
対応については問題ありません。
ボンディングの分散で帯域はかなり確保できるので、1.5倍程度は問題ないという判断からRISTを使おうと思いました。

配信してみる

RISTでの配信設定

OBSの設定は以下のように変更します。

rist://{変換サーバのIP}:20012?rist_profile=advanced&buffer_size=2000

rist_profileはadvancedというRISTのプロファイルになります。エラー訂正が高いプロファイルです。
buffer_sizeは配信のバッファーのサイズを指定します。今回は2000KBになります。

変換サーバの方もRISTで受けるため以下のように変更します。

#!/bin/bash
while true
do
    ffmpeg -i rist://@{変換サーバのIP}:20012?rist_profile=advanced&buffer_size=2000  -c:v libx264 -preset fast -b:v 6000k -maxrate 6000k -bufsize 12000k -c:a aac -b:a 160k -f flv rtmp://live.twitch.tv/app/{{twitchのプライマリストリームキー}} >> /var/log/stream.log 2>&1
    echo "FFmpeg crashed on $(date) -- restarting" >> /var/log/stream.log 2>&1
    sleep 1
done

@の有無で送受信側を設定します。@があると受信側になります。

この状態で配信してみる

同じ構成でストリーミングプロトコルをSRTからRISTに変更した上で再度配信してみました。


ほぼ同じ時間、場所の西湘PA下り(西湘バイパス)で静止状態で配信しました。

youtu.be

ここでブロックノイズが出た秒数の割合は0%でした。


走行中の海側の配信も試してみましたが、問題ありませんでした。
youtu.be

ただ、より悪い電波状況の箱根新道や山梨県の413号線(富士山付近の山奥)で配信しようとするとブロックノイズだらけになります。

youtu.be

山道では、ボンディングを合わせた上りの帯域がそもそも足りない可能性があるため、
ボンディングをしたとしても難しい場所があるようです。

また、高速道路などのトンネル(具体的には東京湾トンネル)では、
AU単独回線よりもブロックノイズが発生するという事態が発生しました。

youtu.be

これは、RISTは再送がないため、分散している回線が全て急激に悪くなった場合、
パケロスが閾値を超えて対応できなくなり、配信が止まってしまうと考察できます。

このことから、UDPのボンディングは相当難しく、
業務用ボンディング機器などを販売している企業はこの点が強みになっているというのを実感しました。

まとめ

今回、外配信の改良をしてみて、やはりオープンソースだけでは難しいというのを実感しました。
実は、OpenMPTCProuterでボンディングをなんとかできないかとかなりの時間を費やしたのですが、
調べるにつれて難しいのではないかと思い始めて
有料サービスのSpeedifyを使ってみると全部解決したので、
有料サービスはすごいということを改めて実感しました。

今回は、RISTやSRTなどをいろいろ試しましたが、
部分部分で良くなったものはあったものの、最適解というものは存在しませんでした。
色々オープンなプロトコルがあるにもかかわらず、有料のボンディング配信機器・専門企業が存在するということは、
やはりボンディングでの外配信が難しいということを実感しました。
今後、H.265(HEVC)の半分の帯域で済むと言われるH.266(VVC)が普及したり、
マルチパスを前提としたQUICベースのストリーミングプロトコルが登場したり、
全域が5Gモバイル通信でそもそもこういった考慮をする必要がなくなれば、
こう言った試行錯誤をしなくてもいい時代が来るかもしれないので
それまでいろいろ試していこうかなと思います。

採用情報

虎の穴ラボでは一緒に働く仲間を募集中です!
この記事を読んで、興味を持っていただけた方はぜひ弊社の採用情報をご覧ください。
toranoana-lab.co.jp