[vlc-devel] [PATCH 6 of 6] dshow: try to improve multithreading code for RAW sample grabbing

Edouard Gomez ed.gomez at free.fr
Fri Oct 10 22:24:23 CEST 2008


# HG changeset patch
# User Edouard Gomez <ed.gomez at free.fr>
# Date 1223648709 -7200
# Node ID e9554b6d7d7c4d762ee2e3caab1d8d214daa8ae4
# Parent  51345cf594f5d2a250ee46cc0370a96a2b80e656
dshow: try to improve multithreading code for RAW sample grabbing

This patch tries to address two theoritical problems:
 - The filter capturepin should not lock p_sys->lock. By chance, win32 mt
   locking is recursive by default.
    - Do not lock again, this makes things clearer for poor POSIX coders like
      me.
 - The current code does not try to push samples as fast as it receives them.
   This is caused by the arbitrary msleep call which can differ sample delivery
   with up to 10ms delay. Moreover, only a single sample at a time was processed
   either for audio or for video.
    - Use MT condition instead of sleep so no artificial delay is introduced in
      the delivery chain.
    - Process all available samples at once.

diff --git a/modules/access/dshow/dshow.cpp b/modules/access/dshow/dshow.cpp
--- a/modules/access/dshow/dshow.cpp
+++ b/modules/access/dshow/dshow.cpp
@@ -279,6 +279,8 @@
     es_out_id_t     *p_es;
 
     bool      b_pts;
+
+    deque<VLCMediaSample> samples_queue;
 } dshow_stream_t;
 
 /*****************************************************************************
@@ -1715,85 +1717,90 @@
 static int Demux( demux_t *p_demux )
 {
     access_sys_t *p_sys = (access_sys_t *)p_demux->p_sys;
-    dshow_stream_t *p_stream = NULL;
-    VLCMediaSample sample;
-    int i_data_size, i_stream;
-    uint8_t *p_data;
-    block_t *p_block;
+    int i_stream;
+    int i_found_samples;
 
+    i_found_samples = 0;
     vlc_mutex_lock( &p_sys->lock );
 
-    /* Try to grab an audio sample (audio has a higher priority) */
-    for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
+    while ( !i_found_samples )
     {
-        p_stream = p_sys->pp_streams[i_stream];
-        if( p_stream->mt.majortype == MEDIATYPE_Audio &&
-            p_stream->p_capture_filter &&
-            p_stream->p_capture_filter->CustomGetPin()
-              ->CustomGetSample( &sample ) == S_OK )
-        {
-            break;
-        }
-    }
-    /* Try to grab a video sample */
-    if( i_stream == p_sys->i_streams )
-    {
+        /* Try to grab samples from all streams */
         for( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
         {
-            p_stream = p_sys->pp_streams[i_stream];
+            dshow_stream_t *p_stream = p_sys->pp_streams[i_stream];
             if( p_stream->p_capture_filter &&
                 p_stream->p_capture_filter->CustomGetPin()
-                    ->CustomGetSample( &sample ) == S_OK )
+                ->CustomGetSamples( p_stream->samples_queue ) == S_OK )
             {
-                break;
+                i_found_samples = 1;
             }
+        }
+
+        if ( !i_found_samples)
+        {
+            /* Didn't find any audio nor video sample, just wait till the
+             * dshow thread pushes some samples */
+            vlc_cond_wait( &p_sys->wait, &p_sys->lock );
+            /* Some DShow thread pushed data, or the OS broke the wait all
+             * by itself. In all cases, it's *strongly* advised to test the
+             * condition again, so let the loop do the test again */
         }
     }
 
     vlc_mutex_unlock( &p_sys->lock );
 
-    if( i_stream == p_sys->i_streams )
+    for ( i_stream = 0; i_stream < p_sys->i_streams; i_stream++ )
     {
-        /* Sleep so we do not consume all the cpu, 10ms seems
-         * like a good value (100fps) */
-        msleep( 10000 );
-        return 1;
-    }
+        int i_samples;
+        dshow_stream_t *p_stream = p_sys->pp_streams[i_stream];
 
-    /*
-     * We got our sample
-     */
-    i_data_size = sample.p_sample->GetActualDataLength();
-    sample.p_sample->GetPointer( &p_data );
+        i_samples = p_stream->samples_queue.size();
+        while ( i_samples > 0 )
+        {
+            int i_data_size;
+            uint8_t *p_data;
+            block_t *p_block;
+            VLCMediaSample sample;
 
-    REFERENCE_TIME i_pts, i_end_date;
-    HRESULT hr = sample.p_sample->GetTime( &i_pts, &i_end_date );
-    if( hr != VFW_S_NO_STOP_TIME && hr != S_OK ) i_pts = 0;
+            sample = p_stream->samples_queue.front();
+            p_stream->samples_queue.pop_front();
 
-    if( !i_pts )
-    {
-        if( p_stream->mt.majortype == MEDIATYPE_Video || !p_stream->b_pts )
-        {
-            /* Use our data timestamp */
-            i_pts = sample.i_timestamp;
-            p_stream->b_pts = true;
+            i_data_size = sample.p_sample->GetActualDataLength();
+            sample.p_sample->GetPointer( &p_data );
+
+            REFERENCE_TIME i_pts, i_end_date;
+            HRESULT hr = sample.p_sample->GetTime( &i_pts, &i_end_date );
+            if( hr != VFW_S_NO_STOP_TIME && hr != S_OK ) i_pts = 0;
+
+            if( !i_pts )
+            {
+                if( p_stream->mt.majortype == MEDIATYPE_Video || !p_stream->b_pts )
+                {
+                    /* Use our data timestamp */
+                    i_pts = sample.i_timestamp;
+                    p_stream->b_pts = true;
+                }
+            }
+
+            i_pts /= 10; /* Dshow works with 100 nano-seconds resolution */
+
+#if 0
+            msg_Dbg( p_demux, "Read() stream: %i, size: %i, PTS: %"PRId64,
+                     i_stream, i_data_size, i_pts );
+#endif
+
+            p_block = block_New( p_demux, i_data_size );
+            vlc_memcpy( p_block->p_buffer, p_data, i_data_size );
+            p_block->i_pts = p_block->i_dts = i_pts;
+            sample.p_sample->Release();
+
+            es_out_Control( p_demux->out, ES_OUT_SET_PCR, i_pts > 0 ? i_pts : 0 );
+            es_out_Send( p_demux->out, p_stream->p_es, p_block );
+
+            i_samples--;
         }
     }
-
-    i_pts /= 10; /* Dshow works with 100 nano-seconds resolution */
-
-#if 0
-    msg_Dbg( p_demux, "Read() stream: %i, size: %i, PTS: %"PRId64,
-             i_stream, i_data_size, i_pts );
-#endif
-
-    p_block = block_New( p_demux, i_data_size );
-    vlc_memcpy( p_block->p_buffer, p_data, i_data_size );
-    p_block->i_pts = p_block->i_dts = i_pts;
-    sample.p_sample->Release();
-
-    es_out_Control( p_demux->out, ES_OUT_SET_PCR, i_pts > 0 ? i_pts : 0 );
-    es_out_Send( p_demux->out, p_stream->p_es, p_block );
 
     return 1;
 }
diff --git a/modules/access/dshow/filter.cpp b/modules/access/dshow/filter.cpp
--- a/modules/access/dshow/filter.cpp
+++ b/modules/access/dshow/filter.cpp
@@ -354,21 +354,49 @@
     FreeMediaType(cx_media_type);
 }
 
+/**
+ * Returns the complete queue of samples that have been received so far.
+ * Lock the p_sys->lock before calling this function.
+ * @param samples_queue [out] Empty queue that will get all elements from
+ * the pin queue.
+ * @return S_OK if a sample was available, S_FALSE if no sample was
+ * available
+ */
+HRESULT CapturePin::CustomGetSamples( deque<VLCMediaSample> &external_queue )
+{
+#if 0 //def DEBUG_DSHOW
+    msg_Dbg( p_input, "CapturePin::CustomGetSamples: %d samples in the queue", samples_queue.size());
+#endif
+
+    if( !samples_queue.empty() )
+    {
+        external_queue.swap(samples_queue);
+        return S_OK;
+    }
+    return S_FALSE;
+}
+
+/**
+ * Returns a sample from its sample queue. Proper locking must be done prior
+ * to this call. Current dshow code protects the access to any sample queue
+ * (audio and video) with the p_sys->lock
+ * @param vlc_sample [out] Address of a sample if sucessfull. Undefined
+ * otherwise.
+ * @return S_OK if a sample was available, S_FALSE if no sample was
+ * available
+ */
 HRESULT CapturePin::CustomGetSample( VLCMediaSample *vlc_sample )
 {
 #if 0 //def DEBUG_DSHOW
     msg_Dbg( p_input, "CapturePin::CustomGetSample" );
 #endif
 
-    vlc_mutex_lock( &p_sys->lock );
     if( samples_queue.size() )
     {
         *vlc_sample = samples_queue.back();
         samples_queue.pop_back();
-        vlc_mutex_unlock( &p_sys->lock );
         return S_OK;
     }
-    vlc_mutex_unlock( &p_sys->lock );
     return S_FALSE;
 }
 
diff --git a/modules/access/dshow/filter.h b/modules/access/dshow/filter.h
--- a/modules/access/dshow/filter.h
+++ b/modules/access/dshow/filter.h
@@ -131,6 +131,8 @@
 
     /* Custom methods */
     HRESULT CustomGetSample( VLCMediaSample * );
+    HRESULT CustomGetSamples( deque<VLCMediaSample> &external_queue );
+
     AM_MEDIA_TYPE &CustomGetMediaType();
 };
 



More information about the vlc-devel mailing list