Note that there are some explanatory texts on larger screens.

plurals
  1. POPrevent frame dropping while saving frames to disk
    primarykey
    data
    text
    <p>I am trying to write C++ code which saves incoming video frames to disk. <strong>Asynchronously</strong> arriving frames are pushed onto queue by a producer thread. The frames are popped off the queue by a consumer thread. Mutual exclusion of producer and consumer is done using a mutex. However, I still notice frames being dropped. The dropped frames (likely) correspond to instances when producer tries to push the current frame onto queue but cannot do so since consumer holds the lock. Any suggestions ? I essentially do not want the producer to wait. A waiting consumer is okay for me.</p> <p>EDIT-0 : Alternate idea which does not involve locking. Will this work ?</p> <ol> <li>Producer initially enqueues <code>n</code> seconds worth of video. <code>n</code> can be some small multiple of frame-rate.</li> <li>As long as queue contains <code>&gt;= n</code> seconds worth of video, consumer dequeues on a frame by frame basis and saves to disk.</li> <li>When the video is done, the queue is flushed to disk. </li> </ol> <p>EDIT-1: The frames arrive at ~ 15 fps.</p> <p>EDIT-2 : Outline of code :</p> <h3>Main driver code</h3> <pre><code> // 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-&gt;Copy(frame); } </code></pre> <h3>Producer</h3> <pre><code>void LVD::PushBufferOntoQueue() { m_queingThread = ::CreateThread( NULL, 0, ThreadFuncPushImageBufferOntoQueue, this, 0, &amp;m_dwThreadID); } DWORD WINAPI LVD::ThreadFuncPushImageBufferOntoQueue(void *arg) { LVD* videoDumper = reinterpret_cast&lt;LVD*&gt;(arg); LocalLock ll( &amp;videoDumper-&gt;m_que_lock, 60*1000 ); videoDumper-&gt;m_frameQue.push(*(videoDumper-&gt;m_buffer)); ll.Unlock(); return 0; } </code></pre> <h3>Consumer</h3> <pre><code>void LVD::DumpQueue() { m_dumpingThread = ::CreateThread( NULL, 0, ThreadFuncDumpFrames, this, 0, &amp;m_dwThreadID); } DWORD WINAPI LVD::ThreadFuncDumpFrames(void *arg) { LVD* videoDumper = reinterpret_cast&lt;LVD*&gt;(arg); LocalLock ll( &amp;videoDumper-&gt;m_que_lock, 60*1000 ); if(videoDumper-&gt;m_frameQue.size() &gt; 0 ) { videoDumper-&gt;m_save_frame=videoDumper-&gt;m_frameQue.front(); videoDumper-&gt;m_frameQue.pop(); } ll.Unlock(); stringstream ss; ss &lt;&lt; videoDumper-&gt;m_saveDir.c_str() &lt;&lt; "\\"; ss &lt;&lt; videoDumper-&gt;m_startTime.c_str() &lt;&lt; "\\"; ss &lt;&lt; setfill('0') &lt;&lt; setw(6) &lt;&lt; videoDumper-&gt;m_frame_id; ss &lt;&lt; ".png"; videoDumper-&gt;m_save_frame.SaveImage(ss.str().c_str()); return 0; </code></pre> <p>}</p> <p>Note:</p> <p>(1) I cannot use C++11. Therefore, <a href="http://www.drdobbs.com/parallel/writing-lock-free-code-a-corrected-queue/210604448?pgno=1" rel="nofollow">Herb Sutter's DDJ article</a> is not an option.</p> <p>(2) I found a <a href="http://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue" rel="nofollow">reference</a> to an unbounded single producer-consumer queue. However, the author(s) state that enqueue(adding frames) is probably not wait-free.</p> <p>(3) I also found <a href="http://www.liblfds.org/" rel="nofollow">liblfds</a>, a C-library but not sure if it will serve my purpose.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload