外部サービス無しでOBSから配信した話

2019-09-24 note obs web

目的

  • 友人間等の少人数(最大5人程度)でWebベースで画面共有を行う
  • VRChatのiwaSyncVideoに流す

既存手法の問題点

  • Discord
    • エンコーダが選べずCPUでエンコードされてしまう
    • 画質やビットレート, 自由度に厳しい制限がある
  • OBS / YouTube Live
    • 最小遅延が6-7秒ほど (少し長い)
    • 版権の自動判定が暴発し、「著作権侵害の申し立て」メールが来て悲しい

改善方針

  • 第三者機関に動画を触らせない
    • 再エンコード回避の為
    • 版権自動判定等の回避の為
  • WANをCDN等のサーバーを介さないため二度通さない
    • 低レイテンシ化の為

尚、以下の恩恵に預かれなくなる。

  • 音声等のメディアの版権の管理が行い易くなる
  • 配信者側アップリンクが視聴者数に関わらず1

これらは画面共有を少人数で行うには、元より不要な機能である。

プロトコル選定

  • RTMP
    • FlashPlayer用のプロトコル
    • TCPの接続若しくはそれをHTTPでラップした形の接続で有る為、煩雑さがある
    • FlashPlayerを使わずに読む事が高難度
    • iwaSyncVideoで読めなかった
  • HTTP Live Streaming (HLS)
    • m3u形式のプレイリストとぶつ切りにされた動画ファイルの単純な形式
    • iwaSyncVideoで読める
  • MPEG-DASH
    • HLS的な物を標準化する動きにより生まれた
    • iwaSyncVideoで読めない

今回、iwaSyncVideoとブラウザ上で正しく表示される事を目標としている為、比較的対応環境の多いHLSを採用した。

HLSとは

以下がHLSのファイル構造である。

 - s.m3u8
 - s1.ts
 - s2.ts
 - s3.ts
 - ...

m3u8のプレイリスト内には、以下の様な最新何件かのtsファイル名が書かれている。

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:5
#EXT-X-MEDIA-SEQUENCE:1710
#EXTINF:4.166667,
s1710.ts
#EXTINF:4.166667,
s1711.ts
#EXTINF:4.166667,
s1712.ts
#EXTINF:4.166667,
s1713.ts
#EXTINF:2.233333,
s1714.ts
#EXT-X-ENDLIST

クライアントは、この拡張されたm3u形式のプレイリストをポーリングし、書かれているファイル名のtsを連続でGET, 再生する。

これらのファイルにHTTPベースでアクセスできる環境を整えるだけで良い。

具体的な方法

映像ソースの自由度を担保するべく、OBSを主軸に扱う。

OBSの 設定 内の 出力 から 出力モード基本 から 詳細 に変更すると、より詳細な設定が可能となる。 が、それでも 配信 の設定の自由度は低い為、 録画 の設定項目を使って配信用のファイルを作っていく。

  • 種別カスタム出力 (ffmpeg)
  • FFmpeg の出力の種類URLに出力
  • ファイルパス または URL をWebサーバー配下に指定する。
    • 今回は /home/user/public_html/s/s.m3u8 とした。
    • ファイルに出力 の場合ダイアログが出るが、特に変なことをしない URLに出力 を選んだ
  • コンテナフォーマットhls
  • 映像ビットレート を任意の値に
    • 3000kbps にした
  • キーフレーム間隔 を任意の値に
    • 今回は2秒間隔の 120 とした (60fpsなので)
    • 短くすると低遅延/安定に成り易いが、容量が大きくなる
    • 長くすると容量が小さくなるが、遅延増大/不安定になる
  • 映像エンコーダlibx264
  • 音声ビットレート を任意の値に
    • 128kbps にした
  • 音声エンコーダaac

これで、iwaSyncVideoに対してのストリームはm3u8へのURLで行える。

と、同時にWebベースでも見たい為同じディレクトリに以下のhtmlファイルを置いた。

<!DOCTYPE html>
<html lang=en>
<head>
  <meta name=viewport content="width=device-width, initial-scale=1.0">
  <title>Streaming</title>
  <style>
    html, body {
      margin: 0;
      width: 100%;
    }
    video {
      width: 100%;
    }
    .container {
      font-family: monospace;
      max-width: 1280px;
      margin: auto;
      width: calc(100%-20px);
      padding-left: 10px;
      padding-right: 10px;
    }
  </style>
</head>
<body>
  <script src=https://cdn.jsdelivr.net/npm/hls.js@latest></script>
  <div class=container>
    <h1>Streaming</h1>
    <video id=video controls preload=none></video>
  </div>
  <script>
    const video = document.getElementById('video');
    if(Hls.isSupported()) {
      const hls = new Hls();
      hls.loadSource('s.m3u8');
      hls.attachMedia(video);
      hls.on(Hls.Events.MANIFEST_PARSED, function() {
        video.play();
      });
    }
  </script>
</body>
</html>

結果的なレイテンシ

運用してみた所、Webページから見た時、4-6秒程の遅延がある。

また、iwaSyncVideoからみると更に4-6秒程の遅延があった。

iwaSyncVideoから見るとレイテンシが増える問題はYouTube Liveでも同様である為、VRChat側の実装の問題と思われる。

やりたいことは大体できたため、今回はこれで良しとする。

Recent Posts

PSXITA on PC

2022-03-26 2022-03-30 note arch pc

PS4向けArch LinuxのPCへのインストール Read More

MDR-100A メンテナンス

2020-07-09 note audio device repair

ヘッドホンから異音がした為、いじった Read More

Realme X2 Proの導入

2020-07-09 note android device smartphone

安く速いスマートフォンを導入した Read More

独自ページからHugoへ乗り換え

2020-06-30 note hugo web

自前フレームワークからHugoへの乗り換え。その利点と欠点。 Read More

AutoImageCompresserの制作

2020-02-22 portfolio booth csharp oss vrchat windows

軽快なファイル同期 (スクリーンショット想定) の為の画像圧縮デーモン Read More