我正在使用C#(.NET 4.0)從WPF項目中捕獲需要保存到磁盤(BMP格式)的高速攝像頭的300幀視頻幀序列。視頻幀需要以接近精確的時間間隔進行捕獲,因此我無法在幀捕獲時將幀保存到磁盤 - 磁盤I/O不可預知,並且會丟棄幀之間的時間間隔。採集卡有大約60個幀緩衝區可用。Semaphore是這個視頻序列捕獲/保存工作的正確工具嗎?
我不確定實施此問題的解決方案的最佳方法是什麼。我最初的想法是創建一個「BufferToDisk」線程,在幀緩衝區變爲可用時保存圖像。在這種情況下,主線程捕獲一個幀緩衝區,然後發信號通知線程指示可以保存幀。問題在於幀被捕獲的速度比線程可以保存文件的速度快,因此需要進行某種同步處理。我在想信號量會是這個工作的好工具。不過,我從來沒有用這種方式使用信號量,所以我不知道如何繼續。
這是一個合理的方法來解決這個問題嗎?如果是這樣,有人可以發佈一些代碼讓我開始?
任何幫助,非常感謝。
編輯: 在查看鏈接的「C#中的線程 - 第2部分」書籍摘錄後,我決定通過調整「ProducerConsumerQueue」類示例來實現解決方案。這裏是我的適應代碼:
class ProducerConsumerQueue : IDisposable
{
EventWaitHandle _wh = new AutoResetEvent(false);
Thread _worker;
readonly object _locker = new object();
Queue<string> _tasks = new Queue<string>();
public ProducerConsumerQueue()
{
_worker = new Thread(Work);
_worker.Start();
}
public void EnqueueTask(string task)
{
lock (_locker) _tasks.Enqueue(task);
_wh.Set();
}
public void Dispose()
{
EnqueueTask(null); // Signal the consumer to exit.
_worker.Join(); // Wait for the consumer's thread to finish.
_wh.Close(); // Release any OS resources.
}
void Work()
{
while (true)
{
string task = null;
lock (_locker)
if (_tasks.Count > 0)
{
task = _tasks.Dequeue();
if (task == null)
{
return;
}
}
if (task != null)
{
// parse the parameters from the input queue item
string[] indexVals = task.Split(',');
int frameNum = Convert.ToInt32(indexVals[0]);
int fileNum = Convert.ToInt32(indexVals[1]);
string path = indexVals[2];
// build the file name
string newFileName = String.Format("img{0:d3}.bmp", fileNum);
string fqfn = System.IO.Path.Combine(path, newFileName);
// save the captured image to disk
int ret = pxd_saveBmp(1, fqfn, frameNum, 0, 0, -1, -1, 0, 0);
}
else
{
_wh.WaitOne(); // No more tasks - wait for a signal
}
}
}
}
在主程序使用類:
// capture bitmap images and save them to disk
using (ProducerConsumerQueue q = new ProducerConsumerQueue())
{
for (int i = 0; i < 300; i++)
{
if (curFrmBuf > numFrmBufs)
{
curFrmBuf = 1; // wrap around to the first frame buffer
}
// snap an image to the image buffer
int ret = pxd_doSnap(1, curFrmBuf, 0);
// build the parameters for saving the frame to image file (for the queue)
string fileSaveParams = curFrmBuf + "," + (i + 1) + "," + newPath;
q.EnqueueTask(fileSaveParams);
curFrmBuf++;
}
}
非常漂亮的類 - 此功能有少量的代碼。
非常感謝您的建議,夥計們。
謝謝 - 它確實看起來像生產者/消費者問題。我會仔細研究一下,看看我能否基於此制定解決方案。 – PIntag 2010-12-01 21:38:56