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

Edouard Gomez ed.gomez at free.fr
Wed Oct 15 00:04:30 CEST 2008


# 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.

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