Commit c7d9a5cd authored by Edouard Gomez's avatar Edouard Gomez Committed by Jean-Baptiste Kempf

dshow: try to improve multithreading code for RAW sample grabbing

# HG changeset patch
# User Edouard Gomez <ed.gomez@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's avatarJean-Baptiste Kempf <jb@videolan.org>
parent 0dd04d07
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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();
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment