着信ビデオフレームをディスクに保存するC++コードを書き込もうとしています。非同期に到着するフレームは、プロデューサースレッドによってキューにプッシュされます。フレームは、コンシューマスレッドによってキューからポップされます。プロデューサーとコンシューマーの相互排除は、ミューテックスを使用して行われます。ただし、フレームがドロップされていることに気付きます。ドロップされたフレームは(おそらく)プロデューサーが現在のフレームをキューにプッシュしようとしたが、コンシューマーがロックを保持しているためにプッシュできない場合に対応します。助言がありますか ?私は本質的にプロデューサーを待たせたくありません。待っている消費者は私にとって大丈夫です。
EDIT-0:ロックを伴わない代替案。これは機能しますか?
- プロデューサーは最初に
n
数秒分のビデオをキューに入れます。n
フレームレートの小さな倍数にすることができます。 - キューに
>= n
数秒分のビデオが含まれている限り、コンシューマーはフレームごとにデキューし、ディスクに保存します。 - ビデオが完了すると、キューはディスクにフラッシュされます。
編集-1:フレームは約15fpsで到着します。
編集-2:コードの概要:
メインドライバーコード
// Main function
void LVD::DumpFrame(const IplImage *frame)
{
// Copies frame into internal buffer.
// buffer object is a wrapper around OpenCV's IplImage
Initialize(frame);
// (Producer thread) -- Pushes buffer onto queue
// Thread locks queue, pushes buffer onto queue, unlocks queue and dies
PushBufferOntoQueue();
// (Consumer thread) -- Pop off queue and save to disk
// Thread locks queue, pops it, unlocks queue,
// saves popped buffer to disk and dies
DumpQueue();
++m_frame_id;
}
void LVD::Initialize(const IplImage *frame)
{
if(NULL == m_buffer) // first iteration
m_buffer = new ImageBuffer(frame);
else
m_buffer->Copy(frame);
}
プロデューサー
void LVD::PushBufferOntoQueue()
{
m_queingThread = ::CreateThread( NULL, 0, ThreadFuncPushImageBufferOntoQueue, this, 0, &m_dwThreadID);
}
DWORD WINAPI LVD::ThreadFuncPushImageBufferOntoQueue(void *arg)
{
LVD* videoDumper = reinterpret_cast<LVD*>(arg);
LocalLock ll( &videoDumper->m_que_lock, 60*1000 );
videoDumper->m_frameQue.push(*(videoDumper->m_buffer));
ll.Unlock();
return 0;
}
消費者
void LVD::DumpQueue()
{
m_dumpingThread = ::CreateThread( NULL, 0, ThreadFuncDumpFrames, this, 0, &m_dwThreadID);
}
DWORD WINAPI LVD::ThreadFuncDumpFrames(void *arg)
{
LVD* videoDumper = reinterpret_cast<LVD*>(arg);
LocalLock ll( &videoDumper->m_que_lock, 60*1000 );
if(videoDumper->m_frameQue.size() > 0 )
{
videoDumper->m_save_frame=videoDumper->m_frameQue.front();
videoDumper->m_frameQue.pop();
}
ll.Unlock();
stringstream ss;
ss << videoDumper->m_saveDir.c_str() << "\\";
ss << videoDumper->m_startTime.c_str() << "\\";
ss << setfill('0') << setw(6) << videoDumper->m_frame_id;
ss << ".png";
videoDumper->m_save_frame.SaveImage(ss.str().c_str());
return 0;
}
ノート:
(1)C++11が使えません。したがって、ハーブサッターのDDJ記事はオプションではありません。
(2)無制限の単一の生産者/消費者キューへの参照を見つけました。ただし、作成者は、エンキュー(フレームの追加)はおそらく待機なしではないと述べています。
(3) Cライブラリであるliblfdsも見つけましたが、それが私の目的に役立つかどうかはわかりません。