【发布时间】:2010-12-01 20:15:34
【问题描述】:
我正在使用 C# (.NET 4.0) 开发一个 WPF 项目,以从需要保存到磁盘的高速摄像机(BMP 格式)捕获 300 个视频帧序列。视频帧需要以近乎精确的时间间隔捕获,因此我无法在捕获帧时将它们保存到磁盘——磁盘 I/O 是不可预测的,并且它会丢弃帧之间的时间间隔。采集卡有大约 60 个可用的帧缓冲区。
我不确定实施解决此问题的最佳方法是什么。我最初的想法是创建一个“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++;
}
}
相当漂亮的类——这个功能的少量代码。
非常感谢您的建议,伙计们。
【问题讨论】:
标签: c# .net wpf video-capture semaphore