[vlc-devel] commit: dshow: try to improve multithreading code for RAW sample grabbing ( Edouard Gomez )

git version control git at videolan.org
Thu Oct 16 01:50:43 CEST 2008


vlc | branch: master | Edouard Gomez <ed.gomez at free.fr> | Wed Oct 15 00:04:30 2008 +0200| [c7d9a5cdacd1afb15ca73a42dbb48f7407bfb8e9] | committer: Jean-Baptiste Kempf 

dshow: try to improve multithreading code for RAW sample grabbing

# HG changeset patch
# User Edouard Gomez <ed.gomez at free.fr>
# Date 1224021637 -7200
# Node ID 0c4727aa17ba532172cae4aded7d16d70ea4ea53
# Parent  8e7c3f94407dc1500438237ac6bf3d484bfba742
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.

Signed-off-by: Jean-Baptiste Kempf <jb at videolan.org>

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=c7d9a5cdacd1afb15ca73a42dbb48f7407bfb8e9
---

 modules/access/dshow/dshow.cpp  |  115 +++++++++++++++++++++------------------
 modules/access/dshow/filter.cpp |   34 +++++++++++-
 modules/access/dshow/filter.h   |    2 +
 3 files changed, 94 insertions(+), 57 deletions(-)

diff --git a/modules/access/dshow/dshow.cpp b/modules/access/dshow/dshow.cpp
index 0748d81..7b2e96a 100644
--- a/modules/access/dshow/dshow.cpp
+++ b/modules/access/dshow/dshow.cpp
@@ -279,6 +279,8 @@ typedef struct dshow_stream_t
     es_out_id_t     *p_es;
 
     bool      b_pts;
+
+    deque<VLCMediaSample> samples_queue;
 } dshow_stream_t;
 
 /*****************************************************************************
@@ -1715,85 +1717,90 @@ static block_t *ReadCompressed( access_t *p_access )
 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++ )
-    {
-        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 )
+    while ( !i_found_samples )
     {
+        /* 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 );
 
-    i_pts /= 10; /* Dshow works with 100 nano-seconds resolution */
+            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 );
+            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();
+            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 );
+            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--;
+        }
+    }
 
     return 1;
 }
diff --git a/modules/access/dshow/filter.cpp b/modules/access/dshow/filter.cpp
index 37c34c7..1022e69 100644
--- a/modules/access/dshow/filter.cpp
+++ b/modules/access/dshow/filter.cpp
@@ -351,21 +351,49 @@ CapturePin::~CapturePin()
     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
index 85951f0..ce7e626 100644
--- a/modules/access/dshow/filter.h
+++ b/modules/access/dshow/filter.h
@@ -131,6 +131,8 @@ class CapturePin: public IPin, public IMemInputPin
 
     /* Custom methods */
     HRESULT CustomGetSample( VLCMediaSample * );
+    HRESULT CustomGetSamples( deque<VLCMediaSample> &external_queue );
+
     AM_MEDIA_TYPE &CustomGetMediaType();
 };
 




More information about the vlc-devel mailing list