2015/11/09(月)IPカメラ(Webcam)リレープログラム / ip-camera-relay.pl

IP Cameraの映像を中継するプログラムです。以下の機能があります。

  • IPカメラへの自動再接続。
  • 複数のIPカメラを登録し、接続できたカメラの映像を中継する。接続が切れたら、次に接続できたカメラに接続する。
  • IPカメラに接続できていない時は、指定した画像(ブランクイメージ)を代わりに送信する。

VLCなどのIPCamストリーム受信ソフトでは、カメラとの接続が切れた場合に自動再接続を行ってくれないものがあります。またカメラと接続が切れたときにブランク画像を挿入したいこともあり、それを実現するためのソフトになります。

プログラム

Gistに置いたので、適当に拾ってください。

  • ip-camera-relay.pl Perl用プログラム
  • ライセンス : GPLv2 or later
  • http転送。パスワードなし。Motion JPEG(以下MJPEG)のみ対応。

使い方

$ ip-camera-relay.pl -p 8888 http://(camera-ip):port/stream-path

クライアント接続用に8888番ポートを開き、指定したカメラに接続します。カメラURLはブラウザから接続するURLではなく、ビデオストリームのURLを指定してください*1

複数のカメラを指定すると、それぞれを順番に接続します。最初に接続できたストリームをクライアントに配信し、カメラとの接続が切れたら次に接続できたカメラの映像を送ります。

どのカメラとも接続できない時は、ブランク画像(標準では640x480の青い画像)を送信します。

その他オプションはヘルプを参照してください。

*1 : ブラウザから接続したりカメラの仕様書を見れば、書かれているかと思います。

WebCamのプロトコル

続きを読む

2015/11/06(金)UPnP/SSDPマルチキャスト中継プログラム(DLNA用)

UPnPのマルチキャストパケットを中継するためのプログラムです。通常、同一ネットワーク内でしか使用できないUPnPを、ルーターを超えて使用できるようになります。

想定

  • DLNAサーバとクライアント(またはコントローラーとレンダー)がルーターを超えて存在する。
  • それぞれネットワークAとBとすれば、A内のPCとB内のPCは互いに通信可能である(NATされていない)。
  • どちらのネットワークにも属するPCが存在する。

「WiFiと有線LAN環境を同一ネットワークにしたくない」ただそれだけなのですが、そのせいでUPnP/DLNAが超えられず大変苦労しました……。

続きを読む

2008/01/15(火)WindowsですべてのインターフェイスからUDPブロードキャスト

要:winsock2

INTERFACE_INFO if_list[20];
unsigned long ifsize;
if (WSAIoctl(sock, SIO_GET_INTERFACE_LIST, 0, 0, &if_list,
	sizeof(if_list), &ifsize, 0, 0) == SOCKET_ERROR)
		throw("Failed Interface List");
int if_num = ifsize / sizeof(INTERFACE_INFO);
for (int i=0; i<if_num; i++) {
	sockaddr_in *adr_ip, *adr_net;
	adr_ip  = (sockaddr_in *)&if_list[i].iiAddress;
	adr_net = (sockaddr_in *)&if_list[i].iiNetmask;
	sockaddr.sin_addr.s_addr  = adr_ip ->sin_addr.s_addr;
	sockaddr.sin_addr.s_addr &= adr_net->sin_addr.s_addr;
	sockaddr.sin_addr.s_addr |= ~(adr_net->sin_addr.s_addr);
	// strcpy(s,inet_ntoa(sockaddr.sin_addr));
	sendto(sock, "Find", 4, 0, (struct sockaddr *)&sockaddr, sizeof(struct sockaddr));
}

2007/05/23(水)UDPをTCPにクローンするプログラム

UDPを受信してTCPにクローンするプログラム(複数クライアント対応)。本当はマルチスレッドで書いてあげるべきなのですが、そこまですると(実現する処理に対して)高級するぎる気がしたのでポーリングにしました。

というのも、TCPの通信エラーとかが出たときに(ブロックしないはずの)ソケットへの書き込み(データの送信)がバッファ一杯になるとストールして(止まって)しまうんですよね。もちろんソケットや書き込み時の関数はノンブロッキングに設定しておいても、です。C ではまだ確認していませんが、Perlで書いたときはそうでした。

TCP/IPはただ通信するだけなら簡単ですが、この手のエラー処理を考えはじめると非常に頭を使います。

プログラム

メイン部のみ。適当に main ルーチンを書けば Windows でも Unix系 でも動きます。

int	max_connections=100;
char	buffer[0x10000];
int	connection_pool[max_connections];

int accept_client(int listen_sock) {
	int sock, len;
	struct sockaddr_in sin;

	// accept
	len = sizeof(sin);
	sock = accept(listen_sock, (struct sockaddr *)&sin, &len);
	if (sock<0) error_return("client accept error");

	// 接続者情報
	printf("[%02d] Connection from %s\n", sock, inet_ntoa(sin.sin_addr));
	// ソケットの設定
	set_non_blocking(sock);
	return sock;
}

//////////////////////////////////////////////////////////////////////////////
// server main
//////////////////////////////////////////////////////////////////////////////
int udp2tcp_server_main(int udp_sock, int tcp_sock) {
	int i;
	char buf[1024];
	// select用の設定
	fd_set fdbits;
	fd_set fdbits_org;
	FD_ZERO(&fdbits_org);
	FD_SET(udp_sock, &fdbits_org);
	FD_SET(tcp_sock, &fdbits_org);

	while(1) {
		// Select
		memcpy(&fdbits, &fdbits_org, sizeof(fdbits_org));
		select(FD_SETSIZE, &fdbits, NULL, NULL, NULL);

		// New connection from TCP
		if ( FD_ISSET(tcp_sock, &fdbits) ) {
			int newsock = accept_client(tcp_sock);
			if (newsock>0) {
				// search for free connection pool point
				for(i=0; i<max_connections; i++)
					if (!connection_pool[i]) break;

				if (i<max_connections) {	// ソケット番号をセーブ
					FD_SET(newsock, &fdbits_org);
					connection_pool[i] = newsock;
					dbg("[%02d] save to connection_pool[%d]\n", newsock, i);
				} else {		// 接続を切る
					printf("Connections max\n");
					close(newsock);
				}
			}
		}

		// Recieved from UDP
		int size = 0;
		if ( FD_ISSET(udp_sock, &fdbits) ) {
			size = recv(udp_sock, buffer, BUF_SIZE, MSG_DONTWAIT);
			if (size<0) error_exit2("UDP recv error(%d)", size);
			dbg("[%02d] Recieved UDP %d bytes\n", udp_sock, size);
		}

		// TCP接続クライアントにデータを送信
		for(i=0; i<max_connections; i++) {
			int sock = connection_pool[i];
			if (!sock) continue;
			// socket からデータ受信
			if ( FD_ISSET(sock, &fdbits) ) {
				int s = recv(sock, buf, 1024, MSG_DONTWAIT);
				if (s<0) {
					FD_CLR(sock, &fdbits_org);
					connection_pool[i] = 0;
					dbg("[%02d] clear to connection_pool[%d]\n", sock, i);
					printf("[%02d] Connection close\n", sock);
					close(sock);
					continue;
				}
			}
			// データ送信
			if (size>0) {
				//int s = write(sock, buf, size);
				int s = send(sock, buf, size, MSG_DONTWAIT);
				dbg("[%02d] write TCP %d bytes\n", sock, s);
			}
		}
	}
}

2007/02/04(日)Windows Media Service(WMS) 代替サーバ wmrelay

wmrelayって?

Windows Media エンコーダ(WME9)には小規模なライブ中継機能(ストリーミングサーバ機能)を持っていますが、最大接続数に制限があり*1、中継元のアップ回線が細いといろいろと不都合が起こります。

Windows Media Services(WMS) などを用いて大規模な中継を行ったり、icecastのように複数の協力者で大規模中継を試みたいところですが、WMS は Windows Serverにしか付属せず、高い上に Windows を外部向けサーバとして運用させるのも気乗りしません。

wmrelay を利用すれば、Linux、FreeBSD、通常のWindowsマシンなどで誰でも手軽に中継サーバを実現できます(mmsプロトコルは非対応です)。協力者を集めれば大規模中継も簡単に行えます。

*1 : 標準で5人、最大で50人まで

ダウンロード

wmrelay_win-img.jpg

ライセンス:GPL (Version 2 or later)

  • wmrelay.lzh Version 2.12
    • (Windows) wmrelay.exe を実行(ファイル単体でok)
    • (Linux/FreeBSD) wmrelay.pl を Perl 5.8.1 以降で実行

変更履歴

  • Ver2.13 2010/04/10 -b オプションの追加。バッファディフォルトを 64 に変更。
  • Ver2.12 2009/08/24 [Windows] EXE化をActivePerl5.10ベースにしました。
  • Ver2.11 2007/03/08 [Windows] GUIで動作しない不具合を修正しました
  • Ver2.10 2007/02/13 [Windows] GUI操作画面を作成
  • Ver2.01 2007/02/05 Mac等で動かない問題を修正(Thanks to RXさん)
  • Ver2.00 2007/02/03 全面書き直し。pushサーバ機能追加
  • Ver1.00 2005/06/07 初公開

Linux/FreeBSD等での動作

Linux, FreeBSDなどではPerl 5.8.1以降でithreadが有効なものが必要です。.plをWindows環境(GUI)で使用する場合は、GUI-Loftのインストールが必要です(参考サイト)。

「perl -V」として実行したとき「useithreads=define」と出力されればOKです。

~$ perl -V
Summary of my perl5 (revision 5 version 8 subversion 8) configuration:
<中略>
hint=recommended, useposix=true, d_sigaction=define
usethreads=define use5005threads=undef useithreads=define usemultiplicity=define

動作確認

  • エンコードソフト:Windows Media Encoder 9 (WME9)
  • 再生ソフト:Windows Media Player 6.4*2/9.x, Winamp, MPlayer(Linux)
  • wmrelay動作環境:FreeBSD 6.2、Ubuntu 6.10(Linux 2.6)、Windows 2000

音声のみ、動画再生共に確認してます。

*2 : WMV9 Codecが必要です

使い方

wmrelayはコマンドラインから起動します。使用例は次のようになります。

配信元 http://192.168.1.50:8888/
送信ポート 標準値(8080)
>wmrelay http://192.168.1.50:8888/
配信元 http://test-stream.dyndns.org:8080/
送信ポート 8000
>wmrelay -p 8000 http://test-stream.dyndns.org:8080/
配信元 http://test-stream.dyndns.org:8080/path/file.asf
送信ポート 9000
最大接続数 200
>wmrelay.pl -p 9000 -m 200 http://test-stream.dyndns.org:8080/path/file.asf

オプションの解説

-hコマンドラインヘルプを表示します
-cCUI(GUIをオフにして)使用します(Windowsでの動作時のみ)
-p [num]送信に利用するポート番号を指定します(省略時:8080)
-m [num]最大接続数を指定します(省略時:100)
-b [num]バッファサイズを指定。16,32,64,128,256,512,1024 どれか(省略時:64)
-l [file]ログファイル名を指定します。%p はポート番号で置き換わります
-f [file]プッシュサーバモードでのパスワードファイルを指定します(後述)
-a [pass]プッシュサーバモードでのパスワードを指定します(後述)
-sリレー元からのパケット受信情報を表示しません
-dデバッグ情報を表示します

最大接続数の目安

回線速度(アップ速度)をストリームのビットレートで割れば目安がわかります。スピードテストサイトなどで「Upload Speed(上り)」を計測してみてください*3

「アップ速度:0.5Mbps ストリーム:136kbps」の場合0.5*1024 / 136 = 3.7647... (connections max)端数は切り捨てて(必ず切り捨てること)3人が理論限界です。

「アップ速度:12.58Mbps ストリーム:226kbps」の場合12.63*1024 / 226 = 57.226... (connections max) 57人が理論限界ですが50人程度にしておくほうが無難です。

*3 : 「Download Speed(下り)」は無関係です

push配信モード

ストリーム受信元URLを指定しないと、wmrelayはpushサーバモードで動作します。このモードでは中継クライアント(Windows Media Encoder9)から中継要求(サーバへのプッシュ要求)があった際に中継が開始されます。

中継先ポートには配信に利用するポート(-p port_number)と同じ番号を指定します。公開ポイントは適当で構いません(wmrelayは公開ポイントを無視します)。

wme9_push.png

また1つのプログラム(1つのポート)につき同時に1つのストリームのみが中継可能です。パスワードを指定しないと誰でも中継可能となりますのでご注意ください。サーバを止めるときは CTRL-C を何度か押してください。

共通パスワードモード

ユーザー名に関わらず、特定のパスワードを入力したクライアントの接続をすべて受け付けるモードです。パスワードは起動時に次のように指定します。

>wmrelay -a password

ユーザー別パスワードモード

起動時にパスワードファイルを指定することで、ユーザー別のパスワードを設定します。

>wmrelay -f password_file

パスワードファイルは「ユーザー名=パスワード」という書式になります。

# この行はコメントです
user1=pass1
user2=himitsu

パスワードの設定されているユーザーが居ない場合や、パスワードファイルがない場合には、誰でも中継可能になりますので注意してください。

クライアント(リスナー)の使いかた

例えば、210.11.22.33 というIPのマシンにおいて、標準状態の 8080 で中継した場合は、クライアントは次のようにアクセスします。

http://210.11.22.33:8080/

ブラウザから .asx ファイルを経由して表示させたい場合は、ブラウザで次のアドレスにアクセスするよう指示します。

http://210.11.22.33:8080/relay.asx

参考資料

OK キャンセル 確認 その他