OBS複数サイト同時配信プラグイン(ソースコード付き)

 

 

雷鳴です。最近OBSプラグインにいろいろいじってる。ここでOBS同時配信プラグインのことを紹介します。

 

1. 現状

OBSは複数サイトに同時配信機能が実装していません。Twitterで「OBS 同時配信」と検索すると、この機能に要求する方は多いようだ。主に以下の方法です。

1.1. OBS複数起動

複数起動はマジで力技の上で、カメラあるいはゲームキャプチャーは複数のOBSに使えません。


1.2. OBSの録画機能を使ってURLに出力する

私も試したことがあります。エンコーダーはメイン配信と共有できないため力技になる可能性があります。また配信制御機能はメイン配信より弱い(再接続、出力フレームレート表示、ネット混雑処理とか)。そして録画保存はできなくなった。


1.3. nginx-rtmpで自前中継サーバーを立つ

サーバー立ちは初心者にとってややむずかしい・・・?


1.4. Restream.ioのサービスを利用する

たしかに力技になれないが有料


1.5. OBSの代わりにXSplitを利用する

これも有料


1.6. RtmpRelayerを利用する

 refer: 

tokaisodachi.com

 

2. 自作プラグイン

OBSのソースコードより、複数サイトに同時配信できます。しかしGUIで操作する方法がありません。 自作プラグインしか仕方ないと思います。

ソースコードに機能があるため、簡単に同時配信プラグインの作りはできます。

2.1 機能

  • 理論的に数が無制限のサイトに同時配信できる
  • エンコーダーはメイン配信と共有も個別設定もできます
  • ビットレートも映像サイズも個別設定できます
  • 配信開始、停止は個別制御できます
  • 配信ステータス別々で表示する
  • 録画機能にノータッチ
  • OBS以外起動すべきソフトはありません

2.2 配布ページ(ダウンロード)

sorayuki.github.io

リリースページ:

github.com

release.zipはDLL形式でビルド済みのプラグインです。

2.3 使い方

2.3.1 インストール

OBSアプリのインストールフォルダに、obs-pluginsとdataがあります。ダウンロードしたアーカイブにobs-pluginsとdataもあります。解凍して上書きしたらインストール完了。

ただしくインストールしたあとOBS起動したら「同時配信」が現れます。ドラッグ&ドロップしてOBSメインウィンドウの側につけます。

f:id:sorayukinoyume:20200404171401p:plain

2.3.2 配信先の追加 と 配信設定

新規配信登録をクリックしたら配信先を追加して設定ウインドウが出ます。

f:id:sorayukinoyume:20200404172250p:plain

RTMPサーバーとキーは、配信サイトから取得できます。OBSで「設定→配信→サービス:カスタム…」とは同じものです。

「OBS本体と同じ」はメイン配信と共有するって意味です。最もCPUに軽いモードですが、映像サイズまたビットレートは個別設定できない。OBS本体からエンコーダーを取得するため一回メイン配信を起動しなければならない(だがダミー先に配信、接続した前に終わるとかしても大丈夫)。

エンコーダーは個別設定するときメイン配信は起動したことなくでも大丈夫。しかし複数エンコーダーの使いは力技でパソコンの重さに注意して下さい。

OKボタンをクリックすると設定の確認はしました。

2.3.3 配信開始、停止

操作は大体OBS本体と同じです。「開始」ボタンをクリックすると配信開始。配信中は「開始」ボタンは「停止」ボタンになります。配信中は出力フレームレートを表示する。ネットワークは混雑の時フレームレートは下がる。

f:id:sorayukinoyume:20200404173338p:plain

2.4 ソースコード

ソースコードはgithubで公開する

github.com

あとがき

昔もOBSに複数サイト同時配信のプラグインを作ってみたけど、OBS本体とプラグインに配信開始、停止繰り返していつの間にクラッシュ可能性があります。デバッグしたらrtmpライブラリにグロバル変数を使ってスレッドセーフになれないって原因は発見しました。

あの時はrtmp-streamのソースコードからもう一つのDLLを作ってダブル配信できました。三つ、あるいは四つサイトに同時配信したいならもっともっと多いDLL作る必要です。

OBS25.0にこのコミットは

obs-outputs: Fix librtmp mbedtls thread safety · obsproject/obs-studio@2b131d2 · GitHub

その問題を対応しました。これで複数DLLの作成は不要になりました。

私自身はYoutube、ニコニコで配信しないので同時配信したい方の要求はよくわかりませんので、ツイッターのhyuさん(@hyutec)の力を借りました。ありがとうございます。

3D関連理論と2D平面に「立方体」を描く

前の会社はPS4、XBOXなどのコンソールゲームを開発する仕事をやってた。
今の仕事はゲーム開発と関連ありませんが、只今春節休み中、特にやることなくて詰まらない。3D関連の理論を復習してあれそれ実験をやってみる。
目標は2D絵の関数で立体に見える立方体を描く。
簡単に理解できるため、マトリクス演算などわりと理解しにくい知識は使わなくてベクトル演算だけ使う。

まず基礎理論を紹介する。2次元直交座標系は、2次元ベクトルは略。使うのは右でXが正、上でYが正。3次元直交座標系は右手系を使う:X軸の方向は右手の指を沿って、Y軸は指先の方向に示すとき、親指の方向はZ軸にする。

立方体の出番だ。立方体の中心は(0, 0, 1)に置く。辺の長さは2なので、頂点は (1/-1, 1/-1, 2/0) 全部八つだ。


(blenderからスクリーンショットを借りる)

六つの面にも「正面」と「反面」がある。正面から観測して見えるが、反面から見れば見えないはず。例えば上の画像に y=1 の面は見えない。
正面はどこへ向くのは易く判断のため、何かのルールがあれば便利になる。このルールは、「頂点を右回り順番で描く表面は正面」だ。原因は、右手座標系でそうすると頂点を連結するベクトルのクロス積の方向は描く表面の正面方向になる。

だから画像の中の立方体の表面で、頂点の連接順番はこうだ。


頂点は右回りで連接する(見える)表面は三つだ。ほかの表面は左回りで連接する(こっちに向いてない)から見えない。
向こうから観測すれば、頂点の連接順番は逆になる。

次の問題はどうすれば2Dのスクリーンで3Dの立方体を表示できる。
現実の立方体を見える原因は、立方体から人の目まで光線がある。そして目から「スクリーンの中の」立方体まで連接する「光線」は決してスクリーンを通過する。スクリーンはただの平面なので、その「光線」はスクリーンと交わす点で光線の色を描いたら2D平面で立体感ある立方体を表示できる。
ならば、その「交わす点」の計算方法を知ったらスクリーンに表示すべき画像は手に入れる。
三角形相似の性質で交わす点を計算できる。

A点(既知)は目で、D点(既知)はスクリーンを通過して見た点。BC点はスクリーン平面にある。AC⊥BC。
ACの長さも既知なので、|AE|=(ベクトルAD)・(ベクトルAC)÷|AC|。←投影
だから|AB|=|AD|÷|AE|×|AC|。
ベクトルABの長さはした後、(ベクトルAB)=(ベクトルAD)÷|AD|×|AB|。
A点もベクトルABも既知になったらB点の座標も知った。
スクリーン平面で2D座標系を作って、B点の座標はスクリーンの座標系に変換(スクリーンに投影)したら2D平面で表示できるようになった。

ソースコード(結果も見える)
https://github.com/sorayuki/Learn3D (learn3d-1.html)


コードは解説して、
3dutil.jsの中にベクトル演算のクラスがある。
「カメラ」は「目」だ。カメラのデータはカメラの位置、方向、スクリーン(projection planar)への距離を含む。立方体の頂点の座標はスクリーン座標に変換できるメソッドも含む。
スクリーンの座標系は、Z軸はカメラの方向と反対する単位ベクトルk(←カメラ方向は見える表面の方向と反対だから)。そしてZ軸と垂直する任意の単位ベクトルiをX軸方向にして、Y軸の方向はZ軸方向のベクトルとX軸方向のベクトルのクロス積jだ(そうしてXとYのクロス積はZ軸の方向)。上の画像に、ベクトルABをスクリーンに投影するとき、座標は (AB・i,AB・j) になる。
DrawRect関数は立方体の表面を描く。正面はカメラ方向に向く表面(頂点は右回り順番で描く表面)だけ描く。

p.s.
なんだか長い時間で日本語で何も書いてなくて忘れそうになった。ツイッターもほとんどあきらめた。復帰したいけど、タイムラインに入れなかった気が多少とも感じる。

この記事を書くとき、学んでなかった専門用語は多くて難しいと思う。辞書とかネット検索エンジンとかのツールを活用して何とかなる。自分以外の人も理解る可能性があるかもって思って…

とりあえずこれからもよろしくね

デレステ譜面フィルター

久しさ記事を書いた。
最近デレステを遊んだ。私は大学生のときから音ゲーに興味が起こる。
そしてネット友はデレステのスクリーンショットを見てくれたあと、始めた。

ユビート遊んだとき、Jubeat Analyzerというツールがあるが、デレステにそんなツールはない。
じゃあ自分でつくろうって思って、QTでこのツールを書く(QTはアンドロイド端末でも動くと聞いた、これであとは遊び機能も付けるかも)。
譜面スクリプト、スクリプト読み込み、拍の計算、ノートの表示
これ全部実装した後、大プロブレムにあった:フレーム制御の方法はわからない。
いろいろ試した後、しばらく放棄した。どう調整してもラグ。あとはStackOverflowで聞くつもりだ。

そしてこのコードはリアルタイムを要求しない場合で使えるかも、と思ってビデオフィルターを作った。

いつか時間があったらまたリアルタイム再生の方法は勉強する。しばらくこのままで
AviUtlフィルター、ソースコートと夢色ハーモニーのMaster+譜面はここにアップロードした
http://www1.axfc.net/u/3648917

AviUtlでファイル→インポート→CGSS Fumen Overlayで譜面スクリプトを読み込める

lstrcmpA ≠ strcmp

多分中二病の発症とか何とか、とりあえず理由は忘れた。
何年前に私は書いたインポートライブラリ作成ツールに、文字列の比較はC言語のstrcmpの代わりにWindows APIのlstrcmpAを使った。
VC用の.libファイルに、二番目のメンバーはこのライブラリーに全部使われるシンボルの集合だ。シンボルに要求は「lexical」順に並べる。*1
それは簡単なアルゴリズムだね:ソート。
ソートの時文字列の比較は必要だ。あの時は私はstrcmpの代わりにlstrcmpAを使った。多分「Windowsから提供のAPIを使ってみたい」だろう、もうわかんない><

あのツールは今夜使った時、使えない.libを作成した。具体的に、linker.exeは時々「LNK2001:外部シンボルは未解決です」とリンクエラーになった。「一部のシンボル」で、「全部」じゃなかった。例えばimpSは使えるがSは使えない。
それは本当におかしい。.libファイルをバイナリ編集ツールで検索したら、シンボルテーブルに確かにそのシンボルがある。

dumpbinツール使って、私のツールで作成した.libファイルの詳しい情報を調べて、不具合の所は発見した

確かに大文字の「S」は小文字の「i」より値が小さいはず?しかもNULL_THUNK_DATAの最初の文字は 0x7f なので、その場所に置くのは決して正しくない。

コードにブレークポイント使って確認して、意外なことは発見した


lstrcmpA("impS", "S")
このexpressionの戻り値は < 0

このlstrcmpAをstrcmpにしていろいろ試したら、今まで問題なし

MSDNでlstrcmpの説明を調べて、

The function calls CompareString, using the current thread locale, and subtracts 2 from the result, to maintain the C run-time conventions for comparing strings. *2

確かに普通のstrcmpではない。

でもこのコードの書いたとき、どうしてlstrcmpAを使ってたのだろう・・・

インポートライブラリ作成のツールのソースコードは、整理終わったらgithubにupするつもり。ちょっと汚いけど

*1: The second linker member includes symbol names in lexical order, which enables faster searching by name. http://download.microsoft.com/download/e/b/a/eba1050f-a31d-436b-9281-92cdfeae4b45/pecoff.doc

*2:http://msdn.microsoft.com/EN-US/library/ms647488(v=VS.85,d=hv.2).aspx

フィボナッチ数の計算

久しぶり、雷鳴です。一昨年7月から社会人になった。いろいろ忙しい(たぶん)ので記事を全然書いてないorz

アルゴリズムに上手なプログラマーはわりに人気のようだ。でも自分はアルゴリズムに下手なんだ。
だからすこしアルゴリズム技が進めばいいと思って、日曜にMITの授業録画(の中国語訳バージョン)を見て勉強した。

その中で新しいフィボナッチ数の計算方法ははじめて知った:
行列

[ 1 1 ]
[ 1 0 ]
を累乗して、その左上の数は「累乗の回数」番目のフィボナッチ数。

累乗も、そのまま a * a * a * a * ... より早い方法がある。
行列[(1 1) (1 0)]はAにして、累乗の回数はnにする。
そしてnはバイナリ表示の方法で、n = b0 * 2^0 + b1 * 2^1 + b2 * 2^2 + b3 * 2^3 + ... にする。
(そのなかで b0, b1, b2, b3...∈{ 0, 1 })
だから A^n = A^(b1 * 2^0) * A^(b2 * 2^1) * A^(b3 * 2^2) * ...
b[x]=0の時、A^(b[x] * 2^x) = A^0 = I
また任意行列Bは IB = B、BI = B だ。
だからこんなループ


R ← I
An ← A
while n ≠ 0
b = n mod 2
if b == 1 then
R ← R * An
An ← An * An
n ← (n - b) / 2
は、Aのn回累乗を計算できる。

さっそくpythonでそんなプログラムを書いてみようと、
https://github.com/sorayuki/practise/blob/master/Fibonacci.py
こうなった。

この方法で、第20000番目のフィボナッチ数は、乗法160回と加法160回でゲットした

暗黙的リンクのライブラリ編集ツール2

一昨日公開したツールで、
Noprefixの意味を誤解した。

Prefixは正規表現で言えば 「[\?\@_]*」 ではなく「[\?\@_]」です。
だからプログラムをまた更新した。

再うpして一昨日の記事にもダウンロードリンクを更新した

STDCALL対策:VC用暗黙的リンクのライブラリ編集ツール(ソース公開)

  DLLを暗黙的リンクする時、インポートライブラリを使用する。
  よくDLLを使うプログラマーたちはこのパターンに詳しいと思う:DEFファイルを書く→LIB.EXEツールでDEFファイルからLIBファイルに変更する→自分のコードにリンクする。
しかしこの場合に、このパターンはよく効けない:

  1. コンパイラーはVC
  2. 関数かStdcall型
  3. エクスポートする識別子に @nn がない

  原因は、VCはソースコード中の関数名を装飾を付く。
  普段で、C言語の場合「int add(int, int);」あるいはC++言語の場合「extern "C" int add(int, int)」という関数は、識別子が_addになる。リンクの時_addと言う識別子を探す。例えばDEFファイルに「add」で書いたらDLLに「add」と言う関数にリンクする、識別子は「_add」。これはデフォルトの「Cdecl」。
  しかし、Stdcall修飾は存在する場合「int __stdcall add(int, int);」の関数の識別子は「_add@8」になる。Cdeclで使う手段はうまく行わなくなる。リンクの時リンカーは識別子「_add@8」を探すが、LIB.exeで作成したインポートライブラリは「_add」しかない。この時エラーが出る。
  対策としてDEFファイルに「add@8」と書いてもうまく行わない。確かにリンカーにエラーが出ないけど、exeを実行する時エラーが出る:DLL側は装飾つきない関数名としてエクスポートする。しかも、EXE側は関数の修飾をCdeclに変更してもダメだ。クラッシュを発生する:関数の引数はアセンブラレベルで呼ばれた関数側で解放して、呼出元ではないから、修飾の変更することは正しくない。
  この問題の対策として、自分はこのツール( http://d.hatena.ne.jp/sorayukinoyume/20140129 )作ったが、この方法はマジで複雑すぎる:VCのリンカーはインポートテーブルを構築する方法を勉強して、バイナリレベルでSectionを構築して、Coff Objectを構築して、最後でLibraryを構築する。うまく実行できるまでコードを書いてデバックして半月ほど掛かった。ツールは使えるが、私はまた何か簡単な方法があるのかなって思って、結局方法を探した。
  MinGWツールセットでdlltoolと言うツールがある。LIB.exeのようなDEFからLIBを作成する機能もあるが、こいつ--kill-atと言うパラメータがある。このパラメータは簡単に言えばDEFファイルの書く「add@8」はリンカー側に識別子は「_add@8」がDLL側に「add」と言う関数にリンクする。もしLIB.exeにもこんな機能があれば・・・
  実はね、VCのインポートライブラリにこういう機能があるが、LIB.exeに実装してないだけ。そして、私はツールを書いて、こんな機能を実装した。LIB.exe /out:xxx.lib /def:xxx.defで作成したLIBファイルを編集するツール。

2014-2-3更新した
変更点:exeはx86として構築する。新しいPC買ってx64のOSを使ってなんかこのツールはうまく動けなくなった。DLLはx86ですから
ダウンロード:http://www1.axfc.net/u/3169399.7z
ソースは変更してない

2014-2-3更新した
.net framework 4.0は必要だ。
ダウンロード:http://www1.axfc.net/u/3162102.zip
Visual Studio 2013 Express、C++/C#。ATL 7.1は必要だ。
ソースコード:http://www1.axfc.net/u/3162104.zip

参考:
インポートライブラリの仕様:
http://msdn.microsoft.com/ja-jp/windows/hardware/gg463119.aspx

MinGW GCCでDLLを使おうとしたがよく分からない:
http://d.hatena.ne.jp/y2q_actionman/20070628

DLL作成の指針やDLLに関連するファイルについて:
http://www.ne.jp/asahi/hishidama/home/tech/vcpp/dllusage.html