From c7d9a5cdacd1afb15ca73a42dbb48f7407bfb8e9 Mon Sep 17 00:00:00 2001 From: Edouard Gomez Date: Wed, 15 Oct 2008 00:04:30 +0200 Subject: [PATCH] dshow: try to improve multithreading code for RAW sample grabbing # HG changeset patch # User Edouard Gomez # 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 --- 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 0748d814a2..7b2e96a321 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 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 37c34c7721..1022e69fa2 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 &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 85951f09a7..ce7e6261db 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 &external_queue ); + AM_MEDIA_TYPE &CustomGetMediaType(); }; -- 2.11.4.GIT