From 8f9a6421c30167b2bf314d512ae70b27d0167bb1 Mon Sep 17 00:00:00 2001 From: Miguel Freitas Date: Mon, 9 Feb 2009 22:09:28 -0200 Subject: Fix race conditions in gapless_switch (ref. kde bug #180339) --- ChangeLog | 1 + src/xine-engine/audio_decoder.c | 6 ++++-- src/xine-engine/audio_out.c | 2 +- src/xine-engine/buffer.h | 3 +++ src/xine-engine/demux.c | 3 +++ src/xine-engine/video_decoder.c | 2 +- src/xine-engine/xine.c | 6 ++++-- src/xine-engine/xine_interface.c | 3 +++ src/xine-engine/xine_internal.h | 1 + 9 files changed, 21 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9968b2f43..33f153b25 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,7 @@ xine-lib (1.1.17) 2009-??-?? decoder remains the default. * Fix a broken size check in the pvr input plugin (ref. CVE-2008-5239). * More malloc checking (ref. CVE-2008-5240). + * Fix race conditions in gapless_switch (ref. kde bug #180339) xine-lib (1.1.16.1) 2009-01-11 * Fix build with older ffmpeg, both internal and in Debian 5.0. diff --git a/src/xine-engine/audio_decoder.c b/src/xine-engine/audio_decoder.c index 5476262d9..855dee372 100644 --- a/src/xine-engine/audio_decoder.c +++ b/src/xine-engine/audio_decoder.c @@ -89,16 +89,18 @@ static void *audio_decoder_loop (void *stream_gen) { if (stream->audio_decoder_plugin) { lprintf ("close old decoder\n"); - + + stream->keep_ao_driver_open = !!(buf->decoder_flags & BUF_FLAG_GAPLESS_SW); _x_free_audio_decoder (stream, stream->audio_decoder_plugin); stream->audio_decoder_plugin = NULL; stream->audio_track_map_entries = 0; stream->audio_type = 0; + stream->keep_ao_driver_open = 0; } running_ticket->release(running_ticket, 0); - if( !stream->gapless_switch ) + if( !(buf->decoder_flags & BUF_FLAG_GAPLESS_SW) ) stream->metronom->handle_audio_discontinuity (stream->metronom, DISC_STREAMSTART, 0); buftype_unknown = 0; diff --git a/src/xine-engine/audio_out.c b/src/xine-engine/audio_out.c index d28c45ea6..43553875e 100644 --- a/src/xine-engine/audio_out.c +++ b/src/xine-engine/audio_out.c @@ -1609,7 +1609,7 @@ static void ao_close(xine_audio_port_t *this_gen, xine_stream_t *stream) { pthread_mutex_unlock(&this->streams_lock); /* close driver if no streams left */ - if (!ite && !this->grab_only && !stream->gapless_switch) { + if (!ite && !this->grab_only && !stream->keep_ao_driver_open) { xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_out: no streams left, closing driver\n"); if (this->audio_loop_running) { diff --git a/src/xine-engine/buffer.h b/src/xine-engine/buffer.h index 718dedd74..7669c38e6 100644 --- a/src/xine-engine/buffer.h +++ b/src/xine-engine/buffer.h @@ -374,6 +374,9 @@ struct buf_element_s { * decoder_info[2] carries denominator for display aspect ratio */ #define BUF_FLAG_ASPECT 0x0800 +/* represent the state of gapless_switch at the time buf was enqueued */ +#define BUF_FLAG_GAPLESS_SW 0x1000 + /* Special buffer types: * Sometimes there is a need to relay special information from a demuxer diff --git a/src/xine-engine/demux.c b/src/xine-engine/demux.c index cfb13831e..5e9cf5a83 100644 --- a/src/xine-engine/demux.c +++ b/src/xine-engine/demux.c @@ -231,15 +231,18 @@ void _x_demux_control_headers_done (xine_stream_t *stream) { void _x_demux_control_start( xine_stream_t *stream ) { buf_element_t *buf; + uint32_t flags = (stream->gapless_switch) ? BUF_FLAG_GAPLESS_SW : 0; pthread_mutex_lock(&stream->demux_mutex); buf = stream->video_fifo->buffer_pool_alloc (stream->video_fifo); buf->type = BUF_CONTROL_START; + buf->decoder_flags = flags; stream->video_fifo->put (stream->video_fifo, buf); buf = stream->audio_fifo->buffer_pool_alloc (stream->audio_fifo); buf->type = BUF_CONTROL_START; + buf->decoder_flags = flags; stream->audio_fifo->put (stream->audio_fifo, buf); pthread_mutex_unlock(&stream->demux_mutex); diff --git a/src/xine-engine/video_decoder.c b/src/xine-engine/video_decoder.c index c88e01714..d3c9e0d34 100644 --- a/src/xine-engine/video_decoder.c +++ b/src/xine-engine/video_decoder.c @@ -160,7 +160,7 @@ static void *video_decoder_loop (void *stream_gen) { running_ticket->release(running_ticket, 0); - if( !stream->gapless_switch ) + if( !(buf->decoder_flags & BUF_FLAG_GAPLESS_SW) ) stream->metronom->handle_video_discontinuity (stream->metronom, DISC_STREAMSTART, 0); diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c index e4e36527f..63a5b7213 100644 --- a/src/xine-engine/xine.c +++ b/src/xine-engine/xine.c @@ -419,6 +419,7 @@ void xine_stop (xine_stream_t *stream) { static void close_internal (xine_stream_t *stream) { int i ; + int gapless_switch = stream->gapless_switch; if( stream->slave ) { xine_close( stream->slave ); @@ -429,7 +430,7 @@ static void close_internal (xine_stream_t *stream) { } } - if( !stream->gapless_switch ) { + if( !gapless_switch ) { /* make sure that other threads cannot change the speed, especially pauseing the stream */ pthread_mutex_lock(&stream->speed_change_lock); stream->ignore_speed_change = 1; @@ -445,7 +446,7 @@ static void close_internal (xine_stream_t *stream) { stop_internal( stream ); - if( !stream->gapless_switch ) { + if( !gapless_switch ) { if (stream->video_out) stream->video_out->set_property(stream->video_out, VO_PROP_DISCARD_FRAMES, 0); if (stream->audio_out) @@ -596,6 +597,7 @@ xine_stream_t *xine_stream_new (xine_t *this, stream->early_finish_event = 0; stream->delay_finish_event = 0; stream->gapless_switch = 0; + stream->keep_ao_driver_open = 0; stream->video_out = vo; if (vo) diff --git a/src/xine-engine/xine_interface.c b/src/xine-engine/xine_interface.c index d1d5a18d9..0438aedfa 100644 --- a/src/xine-engine/xine_interface.c +++ b/src/xine-engine/xine_interface.c @@ -527,6 +527,9 @@ void xine_set_param (xine_stream_t *stream, int param, int value) { case XINE_PARAM_GAPLESS_SWITCH: stream->gapless_switch = !!value; + if( stream->gapless_switch && !stream->early_finish_event ) { + xprintf (stream->xine, XINE_VERBOSITY_DEBUG, "frontend possibly buggy: gapless_switch without early_finish_event\n"); + } break; default: diff --git a/src/xine-engine/xine_internal.h b/src/xine-engine/xine_internal.h index f97ca0b24..945157fc2 100644 --- a/src/xine-engine/xine_internal.h +++ b/src/xine-engine/xine_internal.h @@ -361,6 +361,7 @@ struct xine_stream_s { int early_finish_event; /* do not wait fifos get empty before sending event */ int gapless_switch; /* next stream switch will be gapless */ int delay_finish_event; /* delay event in 1/10 sec units. 0=>no delay, -1=>forever */ + int keep_ao_driver_open; #endif }; -- cgit v1.2.3