summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiguel Freitas <miguelfreitas@users.sourceforge.net>2009-02-09 22:09:28 -0200
committerMiguel Freitas <miguelfreitas@users.sourceforge.net>2009-02-09 22:09:28 -0200
commit8f9a6421c30167b2bf314d512ae70b27d0167bb1 (patch)
treeed5f8b2c71ef01d4df40c8fb2f5b6b9deda2b612
parentb69cc6330e66260238abf75164f18db17337ba20 (diff)
downloadxine-lib-8f9a6421c30167b2bf314d512ae70b27d0167bb1.tar.gz
xine-lib-8f9a6421c30167b2bf314d512ae70b27d0167bb1.tar.bz2
Fix race conditions in gapless_switch (ref. kde bug #180339)
-rw-r--r--ChangeLog1
-rw-r--r--src/xine-engine/audio_decoder.c6
-rw-r--r--src/xine-engine/audio_out.c2
-rw-r--r--src/xine-engine/buffer.h3
-rw-r--r--src/xine-engine/demux.c3
-rw-r--r--src/xine-engine/video_decoder.c2
-rw-r--r--src/xine-engine/xine.c6
-rw-r--r--src/xine-engine/xine_interface.c3
-rw-r--r--src/xine-engine/xine_internal.h1
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
};