        buf->decoder_flags = buf->decoder_flags | BUF_FLAG_FRAME_START;
      }
  
-@@ -733,6 +747,23 @@
+@@ -733,6 +747,23 @@ static void send_ogg_buf (demux_ogg_t *this,
               stream_num, op->bytes, buf->pts, str);
  
      this->video_fifo->put (this->video_fifo, buf);

 static int aac_get_sr_index (uint32_t sample_rate) {
   if (92017 <= sample_rate)
     return 0;
@@ -1455,6 +1510,10 @@
       if (track->compress_algo == MATROSKA_COMPRESS_NONE) {
         track->compress_algo = MATROSKA_COMPRESS_UNKNOWN;
       }

+  { PLUGIN_NONE, 0, "", 0, NULL, NULL }
+};
+
diff --git a/src/xine-engine/audio_decoder.c b/src/xine-engine/audio_decoder.c
index 6a0688f..3d3ae0c 100644
--- a/src/xine-engine/audio_decoder.c
+++ b/src/xine-engine/audio_decoder.c
@@ -42,6 +42,36 @@
 #include <xine/xine_internal.h>
 #include <xine/xineutils.h>
 
+/* if updating SPU decoders for audio only streams, the decoders might crash
+   as they'll expect a valid video out - so only allow the ones we know are ok */
+static int is_suitable_audio_spu(int type)
+{
+  int streamtype = type & 0xFFFF0000;
+  switch (streamtype) {
+    case BUF_SPU_KATE:
+      return 1;
+    default:
+      return 0;
+  }
+}
+
+static void update_spu_decoder (xine_stream_t *stream, int type) {
+
+  int streamtype = (type>>16) & 0xFF;
+  
+  if( stream->spu_decoder_streamtype != streamtype ||
+      !stream->spu_decoder_plugin ) {
+    
+    if (stream->spu_decoder_plugin)
+      _x_free_spu_decoder (stream, stream->spu_decoder_plugin);
+          
+    stream->spu_decoder_streamtype = streamtype;
+    stream->spu_decoder_plugin = _x_get_spu_decoder (stream, streamtype);
+
+  }
+  return ;
+}
+
 static void *audio_decoder_loop (void *stream_gen) {
 
   buf_element_t   *buf = NULL;
@@ -52,11 +82,14 @@ static void *audio_decoder_loop (void *stream_gen) {
   xine_ticket_t   *running_ticket = stream->xine->port_ticket;
   int              running = 1;
   int              prof_audio_decode = -1;
+  int              prof_spu_decode = -1;
   uint32_t         buftype_unknown = 0;
   int              audio_channel_user = stream->audio_channel_user;
 
   if (prof_audio_decode == -1)
     prof_audio_decode = xine_profiler_allocate_slot ("audio decoder/output");
+  if (!stream->video_out && prof_spu_decode == -1)
+    prof_spu_decode = xine_profiler_allocate_slot ("SPU decoder/output");
 
   while (running) {
 
@@ -96,6 +129,12 @@ static void *audio_decoder_loop (void *stream_gen) {
 	stream->audio_type = 0;
       }
       
+      if (!stream->video_out && stream->spu_decoder_plugin) {
+        _x_free_spu_decoder (stream, stream->spu_decoder_plugin);
+        stream->spu_decoder_plugin = NULL;
+        stream->spu_track_map_entries = 0;
+      }
+
       running_ticket->release(running_ticket, 0);
       
       if( !stream->gapless_switch )
@@ -173,6 +212,11 @@ static void *audio_decoder_loop (void *stream_gen) {
 	stream->audio_track_map_entries = 0;
 	stream->audio_type = 0;
       }
+      if (!stream->video_out && stream->spu_decoder_plugin) {
+        _x_free_spu_decoder (stream, stream->spu_decoder_plugin);
+        stream->spu_decoder_plugin = NULL;
+        stream->spu_track_map_entries = 0;
+      }
       
       running_ticket->release(running_ticket, 0);
       running = 0;
@@ -185,11 +229,14 @@ static void *audio_decoder_loop (void *stream_gen) {
       lprintf ("reset\n");
 
       _x_extra_info_reset( stream->audio_decoder_extra_info );
+      running_ticket->acquire(running_ticket, 0);
       if (stream->audio_decoder_plugin) {
-	running_ticket->acquire(running_ticket, 0);
 	stream->audio_decoder_plugin->reset (stream->audio_decoder_plugin);
-	running_ticket->release(running_ticket, 0);
       }
+      if (stream->spu_decoder_plugin) {
+        stream->spu_decoder_plugin->reset (stream->spu_decoder_plugin);
+      }
+      running_ticket->release(running_ticket, 0);
       break;
           
     case BUF_CONTROL_DISCONTINUITY:
@@ -240,19 +287,19 @@ static void *audio_decoder_loop (void *stream_gen) {
 
     default:
 
-      if (_x_stream_info_get(stream, XINE_STREAM_INFO_IGNORE_AUDIO))
-        break;
-
-      xine_profiler_start_count (prof_audio_decode);
-
-      running_ticket->acquire(running_ticket, 0);
-	  
       if ( (buf->type & 0xFF000000) == BUF_AUDIO_BASE ) {
 	
 	uint32_t audio_type = 0;
 	int      i,j;
 	uint32_t chan=buf->type&0x0000FFFF;
 
+        if (_x_stream_info_get(stream, XINE_STREAM_INFO_IGNORE_AUDIO))
+          break;
+
+        xine_profiler_start_count (prof_audio_decode);
+
+        running_ticket->acquire(running_ticket, 0);
+	  
 	/*
         printf("audio_decoder: buf_type=%08x auto=%08x user=%08x\n",
 	       buf->type, 
@@ -377,17 +424,81 @@ static void *audio_decoder_loop (void *stream_gen) {
 	    }
 	  }
 	}
+
+        if (running_ticket->ticket_revoked)
+          running_ticket->renew(running_ticket, 0);
+        running_ticket->release(running_ticket, 0);
+      
+        xine_profiler_stop_count (prof_audio_decode);
+
+///
+      } else if ( (buf->type & 0xFF000000) == BUF_SPU_BASE ) {
+
+        int      i,j;
+
+        if (stream->video_out || !is_suitable_audio_spu(buf->type))
+          break;
+
+        if (_x_stream_info_get(stream, XINE_STREAM_INFO_IGNORE_SPU))
+          break;
+
+        xine_profiler_start_count (prof_spu_decode);
+
+        running_ticket->acquire(running_ticket, 0);
+      
+        update_spu_decoder(stream, buf->type);
+
+        /* update track map */
+
+        i = 0;
+        while ( (i<stream->spu_track_map_entries) && (stream->spu_track_map[i]<buf->type) ) 
+          i++;
+        
+        if ( (i==stream->spu_track_map_entries)
+             || (stream->spu_track_map[i] != buf->type) ) {
+          xine_event_t  ui_event;
+
+          j = stream->spu_track_map_entries;
+
+          if (j >= 50)
+            break;
+
+          while (j>i) {
+            stream->spu_track_map[j] = stream->spu_track_map[j-1];
+            j--;
+          }
+          stream->spu_track_map[i] = buf->type;
+          stream->spu_track_map_entries++;
+
+	  ui_event.type        = XINE_EVENT_UI_CHANNELS_CHANGED;
+	  ui_event.data_length = 0;
+	  xine_event_send (stream, &ui_event);
+        }
+
+        if (stream->spu_channel_user >= 0) {
+          if (stream->spu_channel_user < stream->spu_track_map_entries)
+            stream->spu_channel = (stream->spu_track_map[stream->spu_channel_user] & 0xFF);
+          else
+            stream->spu_channel = stream->spu_channel_auto;
+        }
+
+        if (stream->spu_decoder_plugin) {
+          stream->spu_decoder_plugin->decode_data (stream->spu_decoder_plugin, buf);
+        }
+
+        if (running_ticket->ticket_revoked)
+          running_ticket->renew(running_ticket, 0);
+        running_ticket->release(running_ticket, 0);
+      
+        xine_profiler_stop_count (prof_spu_decode);
+
+///
+
       } else if( buf->type != buftype_unknown ) {
 	  xine_log (stream->xine, XINE_LOG_MSG, 
 		    _("audio_decoder: error, unknown buffer type: %08x\n"), buf->type );
 	  buftype_unknown = buf->type;
       }
-
-      if (running_ticket->ticket_revoked)
-        running_ticket->renew(running_ticket, 0);
-      running_ticket->release(running_ticket, 0);
-      
-      xine_profiler_stop_count (prof_audio_decode);
     }
 
     /* some decoders require a full reinitialization when audio
diff --git a/src/xine-engine/osd.c b/src/xine-engine/osd.c
index 1d3754d..ddf46a5 100644
--- a/src/xine-engine/osd.c
+++ b/src/xine-engine/osd.c
@@ -299,6 +299,7 @@ static int _osd_show (osd_object_t *osd, int64_t vpts, int unscaled ) {
   rle_elem_t rle, *rle_p=0;
   int x, y;
   uint8_t *c;
+  int ret;
 
   lprintf("osd=%p vpts=%"PRId64"\n", osd, vpts);
   
@@ -415,15 +416,18 @@ static int _osd_show (osd_object_t *osd, int64_t vpts, int unscaled ) {
     this->event.event_type = OVERLAY_EVENT_SHOW;
     this->event.vpts = vpts;
     ovl_manager->add_event(ovl_manager, (void *)&this->event);
+
+    ret = 1;
   } else {
     /* osd empty - hide it */
     _osd_hide(osd, vpts);
+    ret = 0;
   }
   pthread_mutex_unlock (&this->osd_mutex);  
   
   this->stream->xine->port_ticket->release(this->stream->xine->port_ticket, 1);
   
-  return 1;
+  return ret;
 }
 
 /* normal OSD show
@@ -1683,6 +1687,14 @@ static void osd_draw_bitmap(osd_object_t *osd, uint8_t *bitmap,
 
   lprintf("osd=%p at (%d,%d) %dx%d\n",osd, x1,y1, width,height );
 
+  /* prevent overflowing to right and bottom */
+  if (x1+width > osd->width) {
+    width = osd->width-x1;
+  }
+  if (y1+height > osd->height) {
+    height = osd->height-y1;
+  }
+
   /* update clipping area */
   osd->x1 = MIN( osd->x1, x1 );
   osd->x2 = MAX( osd->x2, x1+width );
-- 
1.6.0

