SDL_net と Ethereal

引き続き Live Video Streaming というテーマ。
映像を、ネットで、低遅延で、ガスガス送る。
そのネットワーク部分。

Windows プログラムなので Winsock でも使えばいいのだろうけど
何かの間違いで Linux に移植とかあるかもなので
そのときの手間を考えて SDL_net を使うことに。

SDL_net はマルチプラットフォームなゲームライブラリである
SDL とあわせて使うように作られた
マルチプラットフォームなネットワークライブラリ。
その実体は、Winsock や Berkeley socket の薄ーいラッパ。

特に問題なく使えていたのだが、1つはまったところがあったのでメモ。

UDP で 24bpp 320pixel x 240pixel の画像を 30FPS で送る
(1フレームを300パケットに分割して)といったことをするのだが

それぐらいの大量のデータを送る場合
パケットの送信間隔が短いと大量のパケットロスが起きるのだ。

送信側の送信関数は成功してるのに、受信側で取ってみると
沢山のパケットが無くなっている。

ネットで調べると socket プログラミングにおいて
同様の問題にぶち当たった人がちらほら。
解決策は書いておらず。

原因を調べるために Ethereal を導入。

これを使うと、早い話
マシンからどんなパケットが出ていったのか
マシンにどんなパケットが入ってきたのか
が分かる。

参考ページ:
 Etherealを使おう

パケット監視。
すると、全パケット、送信元からでて、ちゃんと送信先に入っている。

つーことは、PCにパケットが入って、その先の処理…。
SDL_net のソース見ても recvfrom() を呼んでいるだけ。

recvfrom() なんかをキーワードにネット検索。

あ…

参考ページ:
 Programming UNIX Socket FAQ in Japanese
 Programming UNIX Sockets in C - Frequently Asked Questions: UDP/SOCK_DGRAM アプリケーションの作成

ソケットのバッファ? そんなんあるのか。
いや、あってもおかしくないか。
でー、それは、サイズ設定できるの?
…できるらしい。 setsockopt() 。

そんなわけで SDL_net のソースをいじる。

「SDL_net-1.2.5」で「SDLnetUDP.c」の 388 行目(SDLNet_UDP_Open() 内)に


// 送信バッファ拡張
{
int size = 1048576;
setsockopt(sock->channel, SOL_SOCKET, SO_SNDBUF, (char*)&size, (int)sizeof(size));
}

// 受信バッファ拡張
{
int size = 1048576;
setsockopt(sock->channel, SOL_SOCKET, SO_RCVBUF, (char*)&size, (int)sizeof(size));
}
と追加。

この送受信バッファの最大値はいくつなんだろうか。
Linux なんかだとそれを示す定数があるように書いてあったが
Windows の場合はどうなのか分からなかった。

とりあえず試行錯誤であふれない程度に拡張。
Research | - | trackbacks (0)

Visual Studio .NET 2003 でアセンブラ

ついでにもう少しJPEGデコードを高速化。

MPEG-2 VIDEO VFAPI Plug-In のIDCTには
MMXを使って高速化したバージョンも含まれていたので
それも使ってみることにした。

拡張子.asmのファイルはどうコンパイルするのか知らなかったが

プログラマの隠れ里 内の Assemble Programming
でやり方を理解することができた。

ここにあるように、Visual Studio .NET 2003 の場合は
プロジェクトに.asmファイルを加えて
そのファイルのプロパティページのカスタムビルドステップの全般内で

コマンドライン:
ml /c /coff /Cx /nologo /Fo$(OutDir)\ /Fl$(InputName) /Zi $(InputPath)
 (Release時は Zi フラグをはずす)

出力ファイル:
$(OutDir)\$(InputName).obj

とするだけでOK。


結果、さらに処理時間が90%ぐらいに。

エンコード・デコードの高速化は本質ではないのでここら辺で。
Research | - | trackbacks (0)

Visual Studio .NET 用プロファイラ

地味にJPEGデコードを高速化。

やはり、プロファイルをとると効率的に高速化できる。

プロファイラは DevPartner Profiler Community Edition を使わせてもらっている。

Visual Studio .NET 2003 にはプロファイラがついていないので
この存在は非常にありがたい(VC6にはあったのに…)。

処理が重いと分かったビット単位での読み込み等を高速化。

処理時間が90%ぐらいに。
Research | - | trackbacks (0)

JPEG プログラミング

Live Video Streaming にあたって
画像をJPEG圧縮して送るようにしたいということで
JPEGプログラミング。

ただのJPEGであれば既存のライブラリを使えばいいのだが
DCTの結果を他の目的で流用したり
フレーム中の任意のブロックのみエンコードしたり
といったことがしたいので
ライブラリそのままとは行かない。

いい本があったので参考に組んでみる。

JPEG 概念からC++での実装まで 第2版

丁寧な解説と分かりやすいソース。
おかげでエンコード・デコードの流れを理解できた。

しかし、プログラムの方は、ちゃんと動作はするものの
処理時間がかかりすぎて使い物にならなかった。

プロファイルを取ってみればDCT・IDCTが相当重いようだった。

そこで他をあたることにした。

JPEGのエンコード・デコードライブラリとしては
IJG(Independent JPEG Group) のライブラリが有名らしい。

Independent JPEG Group

DCT・IDCTの部分を見れば、なにやら期待できそうな感じだ。
しかしながら、マクロや独自の型が多用されていて
部分的に使うのは難しく感じた。

渋っていたところ、いい物を見つけた。

ファイヤー和田研 内の システムアーキテクチャ論 2004/06/05 実習2

IJGのライブラリからエンコード部分のみ器用に抜き出したソース。

早速試すと、エンコードの処理時間が 1/10 ぐらいに(劇的だな…)。

残るはデコード部分だが、これに関しては

MPEG-2 VIDEO VFAPI Plug-In

のIDCTの部分のソースコードが非常に参考になった。
波長が合うということなのか、読みやすく感じたし
モジュール化がされていて部分的に抜き出し易くなっていた。

ついでに色空間の変換にテーブルを使うことにした。

Software Library の YCbCr→RGB変換Cソース(ver0.01)(02.7.12 bug fixed)

その他参考になりそうなページとしては

Software Laboratory Alpha

があった。

・SIMD Enhanced JPEG Plug-in Ver.0.17
・アセンブリ言語版 DCT ルーチン for IJG JPEG Software

を公開している。


今頃JPEGかよ…という感もあるけど、バリバリ現役の画像形式だし。
大体、JPEG 2000 は?
大分経つけど普及してないよなぁ。
ストレージ容量や回線速度の増えっぷりからして出番ないんじゃない?
名前変えたら? JPEG XP にでもしたら?
Research | - | trackbacks (0)

UDPってどうなのよ?

自動で再送もしてくれず、到着の保証もなく
まぁ、だけれどTCPよりも軽い
そんなUDP。
それってどうなんだ。

UDPが使い物になるかどうかは
実際のネットワークで使ってみて
どの程度パケットロスが起こるかによるだろう。

実はパケロスなんか起きないなら
なんでもUDPにすりゃいい。

ごくたまにしかパケロスしないなら
それなりに使い道はあるだろうし
たまに受信側がACKを返せば
軽いTCPといった感じに使えるだろう。

そうでもなく、しょうもないほどパケロスだらけだったら
そりゃ使い物にならない。

で、実験してみた。

研究室のマシンから自宅のマシンへ
UDPパケットを送ってどの程度パケロスが起きるか調べる。

自宅は
ケーブルインターネット
下り: 8Mbps (ベストエフォート)
上り: 256Kbps (ベストエフォート)

実験中はリモートデスクトップを使用

1パケット 4096+20byte を 秒間 30パケット で 1000パケット送ると 0パケットロス
1パケット 16384+20byte を 秒間 15パケット で 500パケット送ると 500パケットロス
1パケット 8192+20byte を 秒間 30パケット で 1000パケット送ると 33パケットロス
1パケット 8192+20byte を 秒間 30パケット で 1000パケット送ると 9パケットロス
1パケット 4096+20byte を 秒間 60パケット で 2000パケット送ると 5パケットロス
1パケット 4096+20byte を 秒間 60パケット で 2000パケット送ると 8パケットロス
1パケット 2048+20byte を 秒間 120パケット で 4000パケット送ると 49パケットロス

いまいち方針がふらふらなデータな上、やるたびに結果が変わって困る。
一見すると同じデータ量流すにしても細切れにした方がロスは避けられる
ように見えるが
このパケットサイズというのは SDL_net でのパケットサイズであって
これより下の層では適当な大きさに分けられてしまうんではないかという気もする。
だけど、あまり大きなパケットだと全く届かなくなるし…。
ここら辺については調べる必要がある。

まぁ、何にせよ、パケットロスは起こる。
ビデオストリーミングをするのなら
やりとりするデータ量から言っても、まず起こる。

よかった。 これで、先に進めそうだ。
Research | - | trackbacks (1)

デジタル数字専用OCR

PCに画像として取り込まれたデジタル数字のあらわす数値を読み取るOCRが必要だと思った。
ざっと探したが見つからない。
デジタル数字での表示しか結果の出力がない機器というのは多いと思うのだが
その結果の値をPCに取り込みたい場合はどうするのだろう…。

ま、とにかく自作することに。

スクリーンショット:
ocr.png

実行ファイル:
ocr000.zip
Research | - | trackbacks (0)

Live Video Streaming(3)

JPEG圧縮をかけてみた。

vs001.zip

ブロックノイズが出るぐらい、結構めいっぱい圧縮かけるようにした。

で、無線LANで実験。

うおー、滑らか。
あからさまに遅延が減ってる。
これが圧縮の威力か。

でもISDN使うとかいったらまだまだなんだろうな。

それに全然既存の技術だしな…。
Research | - | trackbacks (0)

Live Video Streaming(2)

カメラからの画像を24bppのビットマップとして
無圧縮で送るプログラム作ってみた。

vs000.zip

まだメニューとかステータスバーのメッセージとか未実装気味だけど
「接続」を選んでIPアドレス打ち込めば接続先から画像が送られてくる。
接続先(サーバー)に当たる方はwebカメラがついてたほうが。

1台のマシンで2つ起動して「localhost」とかやってる分には問題ないけど
無線LANで繋いだマシン間でやると遅延がやばいね…。

とりあえずJPEG圧縮でもかけてみようと思う。

あ、ちなみにLGPLライセンスに基づいて配布されているライブラリ「SDL」と「SDL_net」を使っています。
Research | - | trackbacks (0)

Live Video Streaming

リアルタイム性を考慮したビデオストリーミングとでも言うのだろうか。
簡単に言えばなめらかなテレビ電話を作りたいという感じか。

まずはカメラからの入力だが
WindowsでいいということならばDirectShowを使えば
IEEE 1394 ポートに繋いだデジタルビデオやUSB ポート に繋いだWebカメラから
比較的簡単に動画を取り込める。

次にキャプチャしたらものの送受信。
socket使えるようになったからWinsockでもいいのかもしれないが
SDL_netを使っておくことに。
簡単なネットゲーも作れそうだなぁ…などと思いつつ通信部分を作ってさあ実験。

…肝心のデジタルビデオが研究室にしかない。
Webカメラ買うか…と悩んでいたら
数百円で購入して放置していたDiMAGE X20が実はWebカメラになるようで。
なのだけど、テストしてみると電池の減りがハンパ無いのでACアダプタ購入を決意。
オークションでパチモノゲット。

着くのが楽しみ。


参考ページ :
 Hiroaki's Private Page > Capturing with IEEE-1394 Firewire Camera under Windows2000 & DirectX
 加藤研究室 > プログラミング > USBカメラ画像のキャプチャ

今見たらLinuxでのやり方も書いてあるなー。
Research | - | trackbacks (0)

rsync

要はやりたいことは
あるファイル群の編集をあちこちのマシンから行いたい
ということで

――中略――

CVSはCVSで使いたいのだけど
rsyncというのもお手軽ですね。
cygwinで開発することにしたので尚のこと。
ただ、コマンド打ち間違えて逆方向に同期してしまって萎えそうなので
コマンドに別名つけたいと思います。


リモートホストhogehogeに、/home/web/ディレクトリを転送する場合:

$ rsync -avz -e ssh --delete /home/web/ hogehoe:/home/backup/


参考ページ:
rsyncコマンドの使い方
Research | - | trackbacks (0)