一個のカメラ(USB等)を使い、ネットワークで繋がった他のPCに同時にカメラ画像を
リアルタイムで再生したいと思っています。
カメラ画像を表示するアプリは出来ているのですが、
WinSocket等を使い、他PCへ再生中の画像データを転送するには、
カメラ画像の左上から1pixel毎のRGB情報をデータとして転送し、
受け取り側PCで1Pixel毎書き込みする方法しか思いつきません。
1枚の画像なら問題ないと思いますが、動画となると厳しい‥。
もっと効率よく画像データを転送する仕組みがあればご教授お願いします。
>一個のカメラ(USB等)を使い、ネットワークで繋がった他のPCに同時にカメラ画像を
>リアルタイムで再生したいと思っています。
私も全く同じものを作った事があります。
>カメラ画像を表示するアプリは出来ているのですが、
どのように作成していますか?
DirectShowでカメラからの画像を取得しているのですか?
>WinSocket等を使い、他PCへ再生中の画像データを転送するには、
>カメラ画像の左上から1pixel毎のRGB情報をデータとして転送し、
>受け取り側PCで1Pixel毎書き込みする方法しか思いつきません。
>1枚の画像なら問題ないと思いますが、動画となると厳しい‥。
>もっと効率よく画像データを転送する仕組みがあればご教授お願いします。
効率が良いか悪いかは判断できかねますが、
少なくとも
「カメラ画像の左上から1pixel毎のRGB情報をデータとして転送し、
受け取り側PCで1Pixel毎書き込みする方法」
では間違いなく遅くなるでしょう。
以前、私が行った手法を簡単にお教えします。
・DirectShowからカメラの静止画像のバイナリデータをメモリ上に取得する。
・メモリ上でJpegのバイナリデータに変換する。
(決してファイル等に出力しないこと→ファイルIOは重くなります。)
Jpegは劣化するので圧縮率は0%で行う(これでも劣化はします)。
・ソケット通信にてJpegバイナリデータを別の端末に送信する。
・別の端末にソケット通信で送られてきたJpegバイナリデータを
画面に表示する。この時もファイルに出力したりせず、メモリ上のJpeg
バイナリデータから直接画面に表示する。
以上の処理を繰り返し送信すると別の端末でカメラからの映像が
ほぼリアルタイム(多少は画像が遅れたりしますがあまり気にならない
くらいの処理速度)で表示されました。
但し、これはネットワークに負荷を掛けますし、逆にネットワークが
負荷状態にあったりすると気になるくらいカクカク表示になったりもします。
用は環境次第って感じです。ギガビットLAN環境とかで行うとさらに
快適になるかもしれません。
動画をネットワーク越しに送信ということは、ストリーミング動画配信そのものですね。
ネットワーク帯域に余裕があるのであればモーオタさんが書いたような方法も使える
と思いますが、素直に考えると、MPEG-4、H.263、H.264(MPEG-4/AVC)、などと
いったストリーミング配信向けのコーデックの出番ではないでしょうか。
具体的にどうすればそれらのコーデックを使えるかは分からないのですが、
少し前のPC系の雑誌には、USBカメラ+PCで自宅から動画をストリーミング配信する
といった記事がよく載っていたので、少し探せば結構情報が集まるのではないかと
思います(無責任)。
この手の記事はオープンソース系のソフトを使っている場合が多いので、その
ソースから情報を引き出せないかな、と妄想。
は、名前間違えた。失礼しました > モーヲタさん。
DirectShowでフィルタつなげばCODECは叩けます。
# 但し、インストールしてあるものだけですが。
その上で、MPEG-2 TSのマルチプレクサ/デマルチプレクサあたりをかまして、
ソースフィルタ、ダンプフィルタあたりをベースにRTP/RTCPの送受信フィルタなど用意。
後は制御アプリを用意すれば(GraphEditでもいいですけど…)完成ですかね。
WindowsMediaPlayer SDKでもストリーミング出来るみたいです。
ヘルプファイルがダウンロード出来ると思います。
社内ネット(http)を作成してそこでストリーミング行うようにする手
もあると思います。
確か、WindowsServerをインストールするとWindowsMediaServerのようなものが
インストール出来たと思います。
ご回答有難う御座います。
返答が遅れてすみません。
カメラからの画像はDirectShowで取得しています。
モーヲタさんの
>・DirectShowからカメラの静止画像のバイナリデータをメモリ上に取得する。
とは例えば静止画像の左上1pixelのRGB情報が赤,次が青だった場合,
0000FF00 FF000000(バイナリはリトルエンディアン?)を画像バイナリデータとして扱っ
てよろしいのでしょうか?
>・メモリ上でJpegのバイナリデータに変換する。
Jpegのバイナリデータに変換とは具体的どのようにすればよろしいのでしょうか?
手がかりが記載されているサイトでもよろしいのでご教授お願いします。
>とは例えば静止画像の左上1pixelのRGB情報が赤,次が青だった場合,
>0000FF00 FF000000(バイナリはリトルエンディアン?)を画像バイナリデータとして
>扱ってよろしいのでしょうか?
何か難しく考えてません?
1ピクセルずつどうこうするのではなくて
DirectShowから一括でビットマップデータを
取得するだけです。1ピクセルずつバイナリデータを
取得したりするのではありませんよ。
RGB情報も特に意識はしません。
>Jpegのバイナリデータに変換とは具体的どのようにすればよろしいのでしょうか?
>手がかりが記載されているサイトでもよろしいのでご教授お願いします。
私は以下のサイトを参考にしましたよ。
http://www.amy.hi-ho.ne.jp/jbaba/jpeg1.htm
但し、上記サイトのサンプルはファイル経由するサンプルなので
それを自分で試行錯誤してメモリ上で変換できるように
改造しました。結構苦戦しましたが、いざ完成したらちょっと
感動しました(笑
簡単に言うと、DirectShowからの静止画像ビットマップバイナリデータを引数で渡して
JPEGにメモリ上で変換後のバイナリデータとサイズを取得する関数およびその
逆変換(JPGからBMPにメモリ上で変換)の関数を自分で作りました。
ネット上を探せばメモリ上で相互変換するサンプルが見つかるかも
しれませんが、私は見つけられなかったので自力で作りました。
モーヲタさんありがとうございます。
メモリ上でjpeg形式に変換したバイナリデータを得る事が出来ました。
が、変換後の圧縮率0%のバイナリデータで約30万byte、圧縮率50%で約3万byte
あります。ギガビットLANを使用しても一度では送信できないので分割になってしまいま
す。一度で送信するには圧縮率を上げれるしかないのでしょうか?
>変換後の圧縮率0%のバイナリデータで約30万byte、圧縮率50%で約3万byte
画像の大きさはいくつですか?
30万byteと言う事は300KBですね?
私がさっき試したら、320 X 240ドットのBMP(DirectShowからの静止画データ
そのまま)で約224KB、Jpeg圧縮率0%で約37KBになり、圧縮率50%で約7KBになります。
仮にreilyさんの画像も320 X 240ドットであれば300KBは
圧縮されるどころか増大してます。
メモリ上でのjpeg圧縮処理に問題がないか確かめてください。
ちなみに補足です。参考程度にしてください。
640 X 480ドットのBMP静止画像で約901KBになり、
jpeg圧縮0%で約106KB、jpeg圧縮率50%で約17KBになります。
また、1024 X 768ドットのBMP静止画像で約2305KBになり、
jpeg圧縮率0%で約238KB、jpeg圧縮率50%で約35KBになります。
>ギガビットLANを使用しても一度では送信できないので分割になってしまいます。
これは送れるはずですよ。ギガビットLANであれば
1000MBの転送率(実際にはもっと下がりますが)が理論上の値なので、
たかだか300KBのデータなんて一瞬で送信できるはずです。
(環境にもよりますが・・・)
実際に問題になるのはソケット自体の制限の仕様ではないでしょうか?
私は受信データサイズはMAXで8192バイトとしてますので
1回にパケットから受信するデータ量は最大でも8192バイトです。
よって320 X 240ドットのjpeg画像のサイズが約37KBなので
全ての静止画像データを取得するのに約5回受信しています。
これが連続で送信されてくるイメージになります。
上記のソケット通信でもほぼリアルタイムで画像は表示されますので
reilyさんの作成されたソケット通信制御処理で重くなっている
ロジックとかないか確認されてみた方が良いかもしれません。
元画像サイズが大きいのではないかと思いますが…分割は回避しきれないと思
います。
そもそもネットワークパケットは分割されるものと思ったほうがいいと思います。
そうすると自前のバッファに1画面分読み込んだ上で処理する等となると思います
が、そうすると何分割されたなどは関係無い筈です。
蛇足ですが、ギガビットLANの解釈が違うと思います。
LANの速度はBitPerSecond、つまり秒間ビット数で表すことが多いです。
そもそもギガビットですよね?
なので最高でもその8分の一、さらにプロトコルヘッダのロス、タイミングやバッファサ
イズ、処理能力などでさらに半分近くまで減る事が多いです。
BPSの接頭辞の単位は1024か1000か忘れましたが、1024としても1024/8/
2=64MBpsです。
まぁ、それでも300KB/s程度は軽くクリアできますから問題ありませんが…。
ぬさん
>そもそもネットワークパケットは分割されるものと思ったほうがいいと思います。
>そうすると自前のバッファに1画面分読み込んだ上で処理する等となると思います
>が、そうすると何分割されたなどは関係無い筈です。
私の誤解するような回答がまずかったですね。
5回受信するというのはあくまで例であって、実際受信するサイズは
受信してみないとわかりません。5000バイト受信するときもあれば
8192バイト受信する場合もありますのでMAX8192バイトと設定していても
5回とは限らないです。
パケットデータの電文フォーマットとして先頭4バイトがデータの全サイズ
を指定してますので実際に受信したサイズと比較して1画面分受信したか
のチェックを行ってます。
>蛇足ですが、ギガビットLANの解釈が違うと思います。
>LANの速度はBitPerSecond、つまり秒間ビット数で表すことが多いです。
>そもそもギガビットですよね?
これもまた私のタイプミスです。
1000MBは1000Mbit/sを書くつもりが1000MBと書いてしまいました。
大変失礼しました。1000MByteではありません。
ちなみに1024 X 768ドットサイズで送信しても
ほぼリアルタイムで表示されますが、私の場合は
カメラの静止画像を320 X 240ドットで取得し、
メモリ上でjpeg圧縮し、クライアントに送信して
受信側のメモリ上で640 X 480ドットに拡大して表示してます。
これでもほぼリアルタイムで表示されます。
>私の誤解するような回答がまずかったですね。
ぁーいや、reilyさんの
>ギガビットLANを使用しても一度では送信できないので分割になってしまいま
す。一度で送信するには圧縮率を上げれるしかないのでしょうか?
に対するレスです。分かりづらくてすいません。
どうやったところで何らかの分割はされるので、分割を回避するのではなく、分割
される事を前提に作るべき、言いたかったのですが…。
モーヲタさん、ぬさん、ご返答ありがとうございます。
サイズは1024x768です。
送信にはTCPを使用すれば分割送受信することが出来ました。
さらにこれをUDPで送受信したいと考えています。
現在画像送信PCの方が受信PCより処理速度(fps)が早いので
受信バッファサイズを上げて対応させようとしているのですが
取りこぼしが発生しているのか、受信バッファサイズを超えてしまうのか
1画面分のデータが取得できない時が結構あります。
まだまだ改良しないといけない所が多々ありますが
基本的な画像転送ロジックが理解出来たので
感謝です。ありがとうございました。