dポイントプレゼントキャンペーン実施中!

PCとPCカメラを使って、
10秒前後の遅延再生する簡易プログラムを
作りたいと思っております。
WEBカメラのドライバのフリーソフト
EWCLIBを利用して、下記ソースまで
作ったのですが、高スペックなPCにも
かかわらず、フレームレートが
ばらつきます。
フレームレートは30にしており、
妥協して15にしても同様の
問題がおこるので、おそらくWindowsかカメラの
自動制御が悪さをしていると思われます。

当方試行錯誤したのですが、ついに行き詰りました。
ソースの改良、ハードの取替え、動作環境の
変更等対策がありましたらご教授願います。

ちなみに高価なものであれば、すでに同機能以上の
ものが世の中にあるのは把握しておりますので、
なるべくなら、安価に仕上げれるものが
望ましいです。

#include <esplib.h>
#include <ewclib.h>
#pragma comment(lib, "winmm.lib")
#include <crtdbg.h>

#define FRAMES 60
#define WX 320
#define WY 240

floata=0,b=0,c=0;

void ESP_Ready(void)
{
ESP_CreateImage(0,"000",0,0,WX,WY,400);
ESP_OpenTextWindow(0,86,512,439,135);

ESP_Printf("初期化中...\n");
int r= EWC_Open(WX,WY,15);
if(r){
ESP_Printf("Error %d\n",r);
return;
}
ESP_Printf("Startをクリックしてください.\n");
}

void ESP_Main(void)
{
int w=0;
int **latesc;
latesc = new int*[FRAMES];
for(int i=0;i<FRAMES;i++){
latesc[i] = new int[WX*WY];
}

for(;;){
a=timeGetTime();
CopyMemory(ESP_VramPtr[0],latesc[w],WX*WY*4);
// フレームバッファを指定
ESP_Select(0);
ESP_Update();


// 新しいフレームが来るまで待つ
for(;;){
Sleep(1);
if(EWC_IsCaptured(0)) break;
}
// フレーム番号 r の表示
c=timeGetTime();
b = c - a;
ESP_Locate(0,5);
ESP_Printf("ewc_time[0]= %f [s]\n",b);
ESP_Locate(0,3);
ESP_Printf("w=%03d\n",w);
EWC_SetBuffer(0,latesc[w]);
w=(w+1)%(FRAMES-1);//wには最後に書き込まれたフレームを指定する
if(ESP_STOP) break;
}

for(int i=0;i<FRAMES;i++){
delete[] latesc[i];
}
delete[] latesc;

ESP_Printf("Stop\n");
}

void ESP_Finish(void)
{
EWC_Close();
}

A 回答 (5件)

>サンプルプログラムの普通の動画再生であれば問題ありませんでした


サンプルプログラムとあなたのプログラムの違いは、バッファリングするかしないかの違いでしょう?
それでは、バッファ長を1にすれば、サンプルプログラムの挙動と一致するのではないのですか?その場合にはきちんと動作しますか?

情報を小出しにされると、こちらから問い合わせをしなければならず、大変です。バッファに10秒溜まったら再生が開始されるのですか。それとも、GUIか何かのボタン押しで再生を開始するのですか。
どれだけのスレッドが走っているのかも重要な情報です。

この回答への補足

ありがとうございます。遅延再生は
連続したものであり、起動時から、
アプリケーションの終了時まで
半永久的に動作するものです。

調査したところ、バッファ長は1であっても
100であってもかわりませんでした。

またWEBカメラの設定を完全手動にしたところ、
速度が上がりました。

とはいっても15FPSより大きくはなりませんでした。

とりあえず、明らかな不良はなくなりましたので、
再度自分で調査してみます。
ありがとうございます。

補足日時:2008/04/11 16:26
    • good
    • 0

ANo.2の


>仮に1フレームずつ送る仕様だったとしたら、一番大事なことは、プログラムをデータ受信に専念させたときに、フレーム間隔毎(30fpsなら33msec毎)にデータがとれるかどうか?を確認することです。
については、どうですか?

画像の時刻と、Windowsの取得時刻の両方を比較する必要がありますが、ぱっと見、画像の時刻は、ewc_timeに入っているのではありませんか?

それから、受信と表示は別スレッドにしているのですか?
CPUはマルチコアでしょうか。データ表示にCPUを使っている間はデータが受信できていない(もしくは、同一バッファ上に上書きされる)と思いますが、そもそもどのようなシステムかわからないので、これ以上はアドバイスできません。

10秒遅延というのは、まずは10秒間データを溜めておき、以後は再生しながら受信を続けるということなのでしょうか?

この回答への補足

たびたびありがとうございます。

遅延というのは断続的に行うもので、再生しながら受信するものです。
画像の取得時間はewc_time、timeGetTime()を使う,もしくは
時間取得に関する関数無しで行いましたが、
いずれにしても明らかに遅くなったり、かと思えば、いきなり速くなったりします。
ちなみにフレームレートを30fpsにしても
速くても15fps位までしかいかず、遅いときは5fps以下になってしまいます。

この波も一定ではなく、また撮影対象の光量を落すと、すぐに処理速度が遅くなるわけではありませんが、しばらくするとずっと5fpsくらいになってしまうケースがあります。

まとめると原因がはっきりしないのです。

EWCLIBはDirectShowをつかっているのでこれのせいかもしれません。

補足日時:2008/04/10 17:17
    • good
    • 0

そういえば、そのライブラリに、最低限これだけでカメラから取得した動画を表示できる、というようなサンプルプログラムはついていませんでしたか。


もし、サンプルプログラムで、フレームレートがばらつかないようなら、あなたのプログラムに問題があることになりますし、ばらつけば、ハードウェアスペックの問題かもしれません。

この回答への補足

ありがとうございます。
サンプルプログラムの普通の
動画再生であれば問題ありませんでしたので、
私のプログラム、Windowsの何らかの制御、またはWEBカメラの自動露出や検知の制御が原因と予測していたのですが、、

プログラムはメモリのリークもないはずですし、変数も動的に
宣言しているので、物理メモリはぜんぜん足りているはずで、
さらにプログラム自体もシンプルこの上ないので、
ドツボにはまっております。

補足日時:2008/04/10 13:35
    • good
    • 0

イメージバッファとはなんですか?表示用のバッファですか。


もしそうなら、データを格納する処理もコメントアウトして下さい。

(CPU、物理メモリは特にスペックを必要としていない…)
から類推するに、表示用のバッファについてのコメントと思うのですが。

>EWCLIB自体は1フレームずつ送っていると思われます。

本当ですか?これ、確認とれてますか。
変数宣言と1フレームずつ送る仕様とは関係がないと思いますよ。
仕様をきちんと確認して下さい。
「思われます」は「あなたが思っているだけ」ということがよくあります。
思い込みからつぶしていかないとバグは消えませんよ。

仮に1フレームずつ送る仕様だったとしたら、一番大事なことは、プログラムをデータ受信に専念させたときに、フレーム間隔毎(30fpsなら33msec毎)にデータがとれるかどうか?を確認することです。
そうすることで、何が問題なのかが見えてきます。

個人的にはIsCapturedの仕様がかなり曖昧な気がします。
取得画像に対しては通常、取得時刻とかフレーム番号とかがついていると思うのですが、そのような情報はないのでしょうか。
質問者さんは、timeGetTime()で自前で作っているように思いますが。

それから1フレームもとりこぼしてはいけないようなプログラムはWindowsでは無理です。取りこぼしも視野に入れて設計する必要があります。

この回答への補足

すべてEWCLIBのヘッダファイル内ですが、
1フレームの取り込みはこの辺だと思います。
ー---------------------------STDMETHODIMP BufferCB(double dblSampleTime, BYTE *pBuffer, long lBufferSize)
{
ewc_bufsize[i]= lBufferSize;
int wx= ewc_wx[i];
int wy= ewc_wy[i];
int byte= lBufferSize/wy;
//画像の上下を逆にしてコピー
for(int y=0; y<wy; y++){
memcpy((unsigned char *)ewc_pbuf[i]+(wy-1-y)*byte, pBuffer+y*byte,byte);
}
ewc_time[i]=dblSampleTime;
return S_OK;
--------------------------------
またバッファはアドレス変更の関数を使っています。
-------------------------------
//バッファアドレスを変更
int EWC_SetBuffer(int num, void *buffer)
{
if(numCheck(num)) return 1;
ewc_pbuf[num]=(int *)buffer;
return 0;
}
ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
当方知識不足のため、ヘッダファイルはいじっておりません。
 
やはりヘッダファイルの無駄な命令を削除し、改造するべきなのでしょうか。

補足日時:2008/04/10 11:49
    • good
    • 0

1.データ受信のみなら、受信速度は安定しているのでしょうか。

(別スレッドで表示プログラムが動いていたら止める)
2.EWC_IsCapturedの前のsleep(1)ですが、1msec待つ保証はないですが、その辺りは大丈夫ですか?これを削ったらどうなりますか。
3.データは必ず1フレームずつ送られてくるのですか。2フレーム分送られてきたりしないのでしょうか。

問題の切り分けをしていかないと、この手の問題はなかなか収束しないと思います。
    • good
    • 0
この回答へのお礼

ありがとうございます。

1.各処理速度を測ったところ、イメージバッファへの
  データの収納に費やす時間にばらつきがあるみたいです。

2.sleepをはずしてもCPUの稼働率が100%になるだけで
  根本的に処理に影響はありません。
  (CPU、物理メモリは特にスペックを必要としていない模様で     す。)

3.変数宣言の段階で間違いがなければ、EWCLIB自体は
  1フレームずつ送っていると思われます。

よろしくおねがいします

お礼日時:2008/04/09 00:56

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!