--- gui/interface.c	2007-10-07 21:49:27.000000000 +0200
+++ gui/interface.c	2007-10-23 15:42:03.000000000 +0200
@@ -46,6 +46,9 @@
 #ifdef USE_DVDREAD
 #include "stream/stream_dvd.h"
 #endif
+#ifdef USE_DVDNAV
+#include "stream/stream_dvdnav.h"
+#endif
 
 int vcd_seek_to_track(void *vcd, int track);
 
@@ -514,6 +517,9 @@
 #ifdef USE_DVDREAD
  dvd_priv_t * dvdp = (dvd_priv_t *) arg;
 #endif 
+#ifdef USE_DVDNAV
+ dvdnav_priv_t * dvdnavp = (dvdnav_priv_t *) arg;
+#endif
 
  if (guiIntfStruct.mpcontext) {
    audio_out = mpctx_get_audio_out(guiIntfStruct.mpcontext);
@@ -590,6 +596,24 @@
         guiIntfStruct.Track=dvd_title + 1;
         break;
 #endif
+#ifdef USE_DVDNAV
+   case guiSetDVDNAV:
+        guiIntfStruct.DVDNAV.titles=dvdnavp->titles_nr;
+        guiIntfStruct.DVDNAV.chapters=dvdnavp->chapters_nr;
+        guiIntfStruct.DVDNAV.current_title=dvdnavp->title;
+        guiIntfStruct.DVDNAV.current_chapter=dvdnavp->part;
+        guiIntfStruct.DVDNAV.nr_of_audio_channels=dvdnavp->nr_of_channels;
+        memcpy( guiIntfStruct.DVDNAV.audio_streams,
+		dvdnavp->audio_streams,
+		sizeof( dvdnavp->audio_streams ) );
+        guiIntfStruct.DVDNAV.nr_of_subtitles=dvdnavp->nr_of_subtitles;
+        memcpy( guiIntfStruct.DVDNAV.subtitles,
+		dvdnavp->subtitles,
+		sizeof( dvdnavp->subtitles ) );
+        guiIntfStruct.DVDNAV.current_title=dvdnavp->title;
+        guiIntfStruct.DVDNAV.current_chapter=dvdnavp->part;
+        break;
+#endif
    case guiSetStream:
 	guiIntfStruct.StreamType=stream->type;
 	switch( stream->type )
@@ -599,6 +623,11 @@
 	       guiGetEvent( guiSetDVD,(char *)stream->priv );
 	       break;
 #endif
+#ifdef USE_DVDNAV
+	  case STREAMTYPE_DVDNAV:
+	       guiGetEvent( guiSetDVDNAV,(char *)stream->priv );
+	       break;
+#endif
 #ifdef HAVE_VCD
 	  case STREAMTYPE_VCD: 
 	       {
@@ -746,6 +775,17 @@
 	       dvd_angle=guiIntfStruct.Angle;
 	       break;
 #endif
+#ifdef USE_DVDNAV
+	  case STREAMTYPE_DVDNAV:
+	       {
+	        char tmp[512];
+		sprintf( tmp,"dvdnav://");
+		guiSetFilename( guiIntfStruct.Filename,tmp );
+	       }
+	       dvd_chapter=guiIntfStruct.Chapter;
+	       dvd_angle=guiIntfStruct.Angle;
+	       break;
+#endif
 	 }
 	//if ( guiIntfStruct.StreamType != STREAMTYPE_PLAYLIST ) // Does not make problems anymore!
 	 {	
@@ -1108,6 +1148,10 @@
 #ifdef USE_DVDREAD
 	if ( (unsigned int)vparam & guiDVD ) memset( &guiIntfStruct.DVD,0,sizeof( guiDVDStruct ) );
 #endif
+#ifdef USE_DVDNAV
+	if ( (unsigned int)vparam & guiDVDNAV )
+	    memset( &guiIntfStruct.DVDNAV,0,sizeof( guiDVDNAVStruct ) );
+#endif
 #ifdef HAVE_VCD
 	if ( (unsigned int)vparam & guiVCD ) guiIntfStruct.VCDTracks=0;
 #endif
--- gui/interface.h	2007-10-07 21:49:27.000000000 +0200
+++ gui/interface.h	2007-10-23 15:42:03.000000000 +0200
@@ -10,6 +10,9 @@
 #ifdef USE_DVDREAD
  #include "stream/stream.h"
 #endif
+#ifdef USE_DVDNAV
+ #include "stream/stream_dvdnav.h"
+#endif
 
 typedef struct
 {
@@ -50,6 +53,22 @@
 } guiDVDStruct;
 #endif
 
+#ifdef USE_DVDNAV
+typedef struct
+{
+ int titles;
+ int chapters;
+ int angles;
+ int current_chapter;
+ int current_title;
+ int current_angle;
+ int nr_of_audio_channels;
+ stream_language_t audio_streams[32];
+ int nr_of_subtitles;
+ stream_language_t subtitles[32];
+} guiDVDNAVStruct;
+#endif
+
 typedef struct
 {
  int message;
@@ -73,6 +92,13 @@
    int			Chapter;
 #endif
 
+#ifdef USE_DVDNAV
+   guiDVDNAVStruct      DVDNAV;
+   int			NavTitle;
+   int			NavAngle;
+   int			NavChapter;
+#endif
+
 #ifdef HAVE_VCD
    int    VCDTracks;
 #endif
@@ -133,6 +159,9 @@
 #define guiSetParameters    16
 #define guiSetAfilter       17
 #define guiSetContext       18
+#ifdef USE_DVDNAV
+#define guiSetDVDNAV        19
+#endif
 
 #define guiSetStop  0
 #define guiSetPlay  1
@@ -141,6 +170,9 @@
 #define guiDVD      	1
 #define guiVCD		2
 #define guiFilenames	4
+#ifdef USE_DVDNAV
+#define guiDVDNAV      	8
+#endif
 #define guiALL		0xffffffff
 
 extern int use_gui;
--- gui/app.h	2007-10-07 21:49:27.000000000 +0200
+++ gui/app.h	2007-10-23 15:42:03.000000000 +0200
@@ -62,6 +62,10 @@
 #define evSetVideo	    46
 #define evSetSubtitle       47
 // 48 ...
+//#ifdef USE_DVDNAV
+#define evPlayDVDNAV	    49
+#define evMenuDVDNAV	    50
+//#endif
 
 #define evExit              1000
 
@@ -81,6 +85,12 @@
 #define evSubtitleLoaded  5011
 #define evSetVCDTrack     5012
 #define evSetURL          5013
+//#ifdef USE_DVDNAV
+#define evSetDVDNAVAudio     5014
+#define evSetDVDNAVSubtitle  5015
+#define evSetDVDNAVTitle     5016
+#define evSetDVDNAVChapter   5017
+//#endif
 
 #define evFName           7000
 #define evMovieTime       7001
--- gui/mplayer/gtk/menu.c	2007-10-07 21:49:27.000000000 +0200
+++ gui/mplayer/gtk/menu.c	2007-10-23 15:42:03.000000000 +0200
@@ -377,6 +377,9 @@
 
 
 GtkWidget * DVDSubMenu;
+#ifdef USE_DVDNAV
+GtkWidget * DVDNAVSubMenu;
+#endif
 GtkWidget * DVDTitleMenu;
 GtkWidget * DVDChapterMenu;
 GtkWidget * DVDAudioLanguageMenu;
@@ -410,6 +413,9 @@
 #ifdef USE_DVDREAD
     AddMenuItem( window1, (const char*)playdvd_xpm, SubMenu,MSGTR_MENU_PlayDVD, evPlayDVD );
 #endif
+#ifdef USE_DVDNAV
+    AddMenuItem( window1, (const char*)playdvd_xpm, SubMenu,MSGTR_MENU_PlayDVDNAV, evPlayDVDNAV );
+#endif
     AddMenuItem( window1, (const char*)url_xpm, SubMenu,MSGTR_MENU_PlayURL, evSetURL );
     AddMenuItem( window1, (const char*)sub_xpm, SubMenu,MSGTR_MENU_LoadSubtitle"   ", evLoadSubtitle );
     AddMenuItem( window1, (const char*)delsub_xpm, SubMenu,MSGTR_MENU_DropSubtitle,evDropSubtitle );
@@ -527,6 +533,87 @@
         gtk_widget_set_sensitive( MenuItem,FALSE );
        }
 #endif
+#ifdef USE_DVDNAV
+   DVDNAVSubMenu=AddSubMenu( window1, (const char*)dvd_xpm, Menu,MSGTR_MENU_DVDNAV );
+    AddMenuItem( window1, (const char*)playdvd_xpm, DVDNAVSubMenu,MSGTR_MENU_PlayDisc"    ", evPlayDVDNAV );
+    MenuItem=AddMenuItem( window1, (const char*)prefs_xpm, DVDNAVSubMenu,MSGTR_MENU_MenuDVDNAV"    ", evMenuDVDNAV );
+    if (guiIntfStruct.DVDNAV.current_title==0)
+        gtk_widget_set_sensitive( MenuItem,FALSE ); else
+        gtk_widget_set_sensitive( MenuItem,TRUE );
+//    AddMenuItem( DVDNAVSubMenu,MSGTR_MENU_ShowDVDMenu, evNone );
+    AddSeparator( DVDNAVSubMenu );
+    DVDTitleMenu=AddSubMenu( window1, (const char*)title_xpm, DVDNAVSubMenu,MSGTR_MENU_Titles );
+     if ( guiIntfStruct.DVDNAV.titles )
+      {
+       char tmp[32]; int i;
+       for ( i=1 ; i<= guiIntfStruct.DVDNAV.titles;i++ )
+        {
+         snprintf( tmp,32,MSGTR_MENU_Title,i);
+         AddMenuCheckItem( window1, (const char*)empty1px_xpm, DVDTitleMenu,tmp,
+			   guiIntfStruct.DVDNAV.current_title == i,
+			   (i << 16) + evSetDVDNAVTitle );
+        }
+      }
+      else
+       {
+        MenuItem=AddMenuItem( window1, (const char*)empty_xpm, DVDTitleMenu,MSGTR_MENU_None,evNone );
+        gtk_widget_set_sensitive( MenuItem,FALSE );
+       }
+    DVDChapterMenu=AddSubMenu( window1, (const char*)chapter_xpm, DVDNAVSubMenu,MSGTR_MENU_Chapters );
+     if ( guiIntfStruct.DVDNAV.chapters )
+      {
+       char tmp[32]; int i;
+       for ( i=1;i <= guiIntfStruct.DVDNAV.chapters;i++ )
+        {
+         snprintf( tmp,32,MSGTR_MENU_Chapter,i );
+         AddMenuCheckItem( window1, (const char*)empty1px_xpm, DVDChapterMenu,tmp,guiIntfStruct.DVDNAV.current_chapter == i,
+			   ( i << 16 ) + evSetDVDNAVChapter );
+        }
+      }
+      else
+       {
+        MenuItem=AddMenuItem( window1, (const char*)empty_xpm, DVDChapterMenu,MSGTR_MENU_None,evNone );
+        gtk_widget_set_sensitive( MenuItem,FALSE );
+       }
+    DVDAudioLanguageMenu=AddSubMenu( window1, (const char*)tongue_xpm, DVDNAVSubMenu,MSGTR_MENU_AudioLanguages );
+     if ( guiIntfStruct.DVDNAV.nr_of_audio_channels )
+      {
+       char tmp[64]; int i, id = guiIntfStruct.demuxer ? ((demuxer_t *)guiIntfStruct.demuxer)->audio->id : audio_id;
+       for ( i=0;i < guiIntfStruct.DVDNAV.nr_of_audio_channels;i++ )
+        {
+	 snprintf( tmp,64,"%s - %s %s",GetLanguage( guiIntfStruct.DVDNAV.audio_streams[i].language ),
+	   ChannelTypes[ guiIntfStruct.DVDNAV.audio_streams[i].type ],
+	   ChannelNumbers[ guiIntfStruct.DVDNAV.audio_streams[i].channels ] );
+//	 if ( id == -1 ) id=audio_id; //guiIntfStruct.DVD.audio_streams[i].id;
+         AddMenuCheckItem( window1, (const char*)dolby_xpm, DVDAudioLanguageMenu,tmp,
+			   id == guiIntfStruct.DVDNAV.audio_streams[i].id,
+			   ( guiIntfStruct.DVDNAV.audio_streams[i].id << 16 ) + evSetDVDNAVAudio );
+        }
+      }
+      else
+       {
+        MenuItem=AddMenuItem( window1, (const char*)empty_xpm, DVDAudioLanguageMenu,MSGTR_MENU_None,evNone );
+        gtk_widget_set_sensitive( MenuItem,FALSE );
+       }
+    DVDSubtitleLanguageMenu=AddSubMenu( window1, (const char*)tonguebla_xpm, DVDNAVSubMenu,MSGTR_MENU_SubtitleLanguages );
+     if ( guiIntfStruct.DVDNAV.nr_of_subtitles )
+      {
+       char tmp[64]; int i;
+       AddMenuItem( window1, (const char*)empty1px_xpm, DVDSubtitleLanguageMenu,MSGTR_MENU_None,( (unsigned short)-1 << 16 ) + evSetDVDNAVSubtitle );
+       for ( i=0;i < guiIntfStruct.DVDNAV.nr_of_subtitles;i++ )
+        {
+	 snprintf( tmp,64,"%s",GetLanguage( guiIntfStruct.DVDNAV.subtitles[i].language ) );
+         AddMenuCheckItem( window1, (const char*)empty1px_xpm, DVDSubtitleLanguageMenu,tmp,
+			   dvdsub_id == guiIntfStruct.DVDNAV.subtitles[i].id,
+			   ( guiIntfStruct.DVDNAV.subtitles[i].id << 16 ) + evSetDVDNAVSubtitle );
+        }
+      }
+      else
+       {
+        MenuItem=AddMenuItem( window1, (const char*)empty_xpm, DVDSubtitleLanguageMenu,MSGTR_MENU_None,evNone );
+        gtk_widget_set_sensitive( MenuItem,FALSE );
+       }
+#endif
 
 //  if ( guiIntfStruct.Playing )
    {
@@ -575,7 +662,7 @@
    }
   
   /* cheap subtitle switching for non-DVD streams */
-  if ( global_sub_size && guiIntfStruct.StreamType != STREAMTYPE_DVD )
+  if ( global_sub_size && guiIntfStruct.StreamType != STREAMTYPE_DVD && guiIntfStruct.StreamType != STREAMTYPE_DVDNAV )
    {
     int i;
     SubMenu=AddSubMenu( window1, (const char*)empty_xpm, Menu, MSGTR_MENU_Subtitles );
--- gui/mplayer/mw.c	2007-10-07 21:49:27.000000000 +0200
+++ gui/mplayer/mw.c	2007-10-23 15:42:03.000000000 +0200
@@ -33,6 +33,8 @@
 
 #define GUI_REDRAW_WAIT 375
 
+#define FIXME_GTK_MENU_ActivateMenuItem_PARAM 1
+
 #include "play.h"
 #include "widgets.h"
 
@@ -80,6 +82,7 @@
 {
  int iparam = (int)param;
  mixer_t *mixer = mpctx_get_mixer(guiIntfStruct.mpcontext);
+ char cmd_str[40];
 
  switch( msg )
   {
@@ -129,6 +132,16 @@
         guiIntfStruct.StreamType=STREAMTYPE_DVD;
 	goto play;
 #endif
+#ifdef USE_DVDNAV
+   case evPlayDVDNAV:
+        guiIntfStruct.DVDNAV.current_title=1;
+        guiIntfStruct.DVDNAV.current_chapter=1;
+        guiIntfStruct.DVDNAV.current_angle=1;
+play_dvdnav_2:
+	gtkSet( gtkClearStruct,0,(void *)(guiALL - guiDVDNAV) );
+	guiIntfStruct.StreamType=STREAMTYPE_DVDNAV;
+	goto play;
+#endif
    case evPlay:
    case evPlaySwitchToPause:
 play:
@@ -178,6 +191,21 @@
 		} 
                break;
 #endif
+#ifdef USE_DVDNAV
+          case STREAMTYPE_DVDNAV:
+	       gtkSet( gtkClearStruct,0,
+		    (void *)(guiALL - guiDVDNAV - guiFilenames) );
+	       if ( !dvd_device ) dvd_device=gstrdup( DEFAULT_DVD_DEVICE );
+	       mplSetFileName( NULL,dvd_device,STREAMTYPE_DVDNAV );
+	       if ( guiIntfStruct.Playing != 2 )
+	        {
+		 guiIntfStruct.Title=guiIntfStruct.DVDNAV.current_title;
+		 guiIntfStruct.Chapter=guiIntfStruct.DVDNAV.current_chapter;
+		 guiIntfStruct.Angle=guiIntfStruct.DVDNAV.current_angle;
+                 guiIntfStruct.DiskChanged=1;
+		}
+               break;
+#endif
          }
 	guiIntfStruct.NewPlay=1;
         mplPlay();
@@ -202,6 +230,50 @@
         goto play_dvd_2;
         break;
 #endif
+#ifdef USE_DVDNAV
+   case evSetDVDNAVSubtitle:
+#ifdef FIXME_GTK_MENU_ActivateMenuItem_PARAM
+        dvdsub_id=gtkPopupMenuParam;
+#else
+        dvdsub_id=iparam;
+#endif
+        sprintf(cmd_str,"sub_select %d",dvdsub_id);
+        mp_input_queue_cmd(mp_input_parse_cmd(cmd_str));
+        break;
+   case evSetDVDNAVAudio:
+#ifdef FIXME_GTK_MENU_ActivateMenuItem_PARAM
+        audio_id=gtkPopupMenuParam;
+#else
+        audio_id=iparam;
+#endif
+        sprintf(cmd_str,"switch_audio %d",audio_id);
+        mp_input_queue_cmd(mp_input_parse_cmd(cmd_str));
+        break;
+   case evSetDVDNAVChapter:
+#ifdef FIXME_GTK_MENU_ActivateMenuItem_PARAM
+        sprintf(cmd_str,"switch_chapter %d",gtkPopupMenuParam);
+#else
+        sprintf(cmd_str,"switch_chapter %d",iparam);
+#endif
+        mp_input_queue_cmd(mp_input_parse_cmd(cmd_str));
+        guiIntfStruct.DVDNAV.current_chapter=iparam;
+        break;
+   case evSetDVDNAVTitle:
+#ifdef FIXME_GTK_MENU_ActivateMenuItem_PARAM
+        sprintf(cmd_str,"switch_title %d",gtkPopupMenuParam);
+#else
+        sprintf(cmd_str,"switch_title %d",iparam);
+#endif
+        mp_input_queue_cmd(mp_input_parse_cmd(cmd_str));
+        guiIntfStruct.DVDNAV.current_title=iparam;
+	guiIntfStruct.DVDNAV.current_chapter=1;
+	guiIntfStruct.DVDNAV.current_angle=1;
+        break;
+   case evMenuDVDNAV:
+        sprintf(cmd_str,"dvdnav 5");
+        mp_input_queue_cmd(mp_input_parse_cmd(cmd_str));
+        break;
+#endif
 
    case evPause:
    case evPauseSwitchToPlay:
@@ -339,6 +411,10 @@
 	  default: movie_aspect=-1;
 	 }
 	wsClearWindow( appMPlayer.subWindow );
+#ifdef USE_DVDNAV
+	if ( guiIntfStruct.StreamType == STREAMTYPE_DVDNAV ) goto play_dvdnav_2;
+	  else
+#endif
 #ifdef USE_DVDREAD
 	if ( guiIntfStruct.StreamType == STREAMTYPE_DVD || guiIntfStruct.StreamType == STREAMTYPE_VCD ) goto play_dvd_2;
 	 else 
--- gui/mplayer/sw.c	2007-10-07 21:49:27.000000000 +0200
+++ gui/mplayer/sw.c	2007-10-23 15:42:03.000000000 +0200
@@ -19,6 +19,18 @@
 extern int             boxMoved;
 extern int             sx,sy;
 extern int             i,pot;
+extern int	enable_mouse_movements;
+
+#ifdef USE_DVDNAV
+#include "input/input.h"
+#include "input/mouse.h"
+//extern int	dvdnav_window_width;
+//extern int	dvdnav_window_height;
+//extern int	dvdnav_mouse_x;
+//extern int	dvdnav_mouse_y;
+//extern int	dvdnav_mouse_button;
+//extern int	dvdnav_mouse_set;
+#endif
 
 void mplSubDraw( void )
 {
@@ -66,8 +78,19 @@
           sx=X; sy=Y;
           msButton=wsPLMouseButton;
           mplSubMoved=0;
+#ifdef USE_DVDNAV
+	  mplayer_put_key(MOUSE_BTN0);
+#endif
           break;
    case wsMoveMouse:
+#ifdef USE_DVDNAV
+	if(enable_mouse_movements)
+            {
+            char cmd_str[40];
+            sprintf(cmd_str,"set_mouse_pos %i %i", X, Y);
+            mp_input_queue_cmd(mp_input_parse_cmd(cmd_str));
+            }
+#endif
           switch ( msButton )
            {
             case wsPLMouseButton:
--- gui/mplayer/common.c	2007-10-07 21:49:27.000000000 +0200
+++ gui/mplayer/common.c	2007-10-23 15:56:25.000000000 +0200
@@ -60,6 +60,15 @@
             else av_strlcat( tmp,MSGTR_NoChapter,tmplen );
           break;
 #endif
+#ifdef USE_DVDNAV
+   case STREAMTYPE_DVDNAV:
+          if ( guiIntfStruct.DVDNAV.current_chapter )
+	    snprintf(tmp,tmplen,MSGTR_Chapter,
+		guiIntfStruct.DVDNAV.current_chapter );
+            else
+	    av_strlcat( tmp,MSGTR_NoChapter,tmplen );
+          break;
+#endif
 #ifdef HAVE_VCD
    case STREAMTYPE_VCD:
         snprintf( tmp,tmplen,MSGTR_VCDTrack,guiIntfStruct.Track );
@@ -164,6 +173,9 @@
 #ifdef USE_DVDREAD
              case STREAMTYPE_DVD:    av_strlcat( trbuf,"d",sizeof( trbuf ) ); break;
 #endif
+#ifdef USE_DVDNAV
+             case STREAMTYPE_DVDNAV: av_strlcat( trbuf,"d",sizeof( trbuf ) ); break;
+#endif
              default:                av_strlcat( trbuf," ",sizeof( trbuf ) ); break;
             }
            break;
--- gui/mplayer/play.c	2007-10-07 21:49:27.000000000 +0200
+++ gui/mplayer/play.c	2007-10-23 15:42:03.000000000 +0200
@@ -92,6 +92,11 @@
      guiIntfStruct.DVD.current_chapter=1;
      guiIntfStruct.DVD.current_angle=1;
 #endif
+#ifdef USE_DVDNAV
+     guiIntfStruct.DVDNAV.current_title=1;
+     guiIntfStruct.DVDNAV.current_chapter=1;
+     guiIntfStruct.DVDNAV.current_angle=1;
+#endif
 
      if ( !appMPlayer.subWindow.isFullScreen && gtkShowVideoWindow)
       {
@@ -279,6 +284,10 @@
    case STREAMTYPE_DVD:
 	break;
 #endif
+#ifdef USE_DVDNAV
+   case STREAMTYPE_DVDNAV:
+	break;
+#endif
 #ifdef HAVE_VCD
    case STREAMTYPE_VCD:
 	break;
@@ -315,6 +324,16 @@
 	guiIntfStruct.Track=guiIntfStruct.DVD.current_title;
 	break;
 #endif
+#ifdef USE_DVDNAV
+   case STREAMTYPE_DVDNAV:
+	if ( --guiIntfStruct.DVDNAV.current_chapter == 0 )
+	 {
+	  guiIntfStruct.DVDNAV.current_chapter=1;
+	  if ( --guiIntfStruct.DVDNAV.current_title <= 0 ) { guiIntfStruct.DVDNAV.current_title=1; stop=1; }
+	 }
+	guiIntfStruct.Track=guiIntfStruct.DVDNAV.current_title;
+	break;
+#endif
 #ifdef HAVE_VCD
    case STREAMTYPE_VCD:
 	if ( --guiIntfStruct.Track == 0 ) { guiIntfStruct.Track=1; stop=1; }
@@ -351,6 +370,16 @@
 	guiIntfStruct.Track=guiIntfStruct.DVD.current_title;
 	break;
 #endif
+#ifdef USE_DVDNAV
+   case STREAMTYPE_DVDNAV:
+	if ( guiIntfStruct.DVDNAV.current_chapter++ == guiIntfStruct.DVDNAV.chapters )
+	 {
+	  guiIntfStruct.DVDNAV.current_chapter=1;
+	  if ( ++guiIntfStruct.DVDNAV.current_title > guiIntfStruct.DVDNAV.titles ) { guiIntfStruct.DVDNAV.current_title=guiIntfStruct.DVDNAV.titles; stop=1; }
+	 }
+	guiIntfStruct.Track=guiIntfStruct.DVDNAV.current_title;
+	break;
+#endif
 #ifdef HAVE_VCD
    case STREAMTYPE_VCD:
 	if ( ++guiIntfStruct.Track > guiIntfStruct.VCDTracks ) { guiIntfStruct.Track=guiIntfStruct.VCDTracks; stop=1; }
--- help/help_mp-en.h	2007-10-07 21:49:32.000000000 +0200
+++ help/help_mp-en.h	2007-10-23 15:43:13.000000000 +0200
@@ -824,6 +824,10 @@
 #define MSGTR_MENU_Track "Track %d"
 #define MSGTR_MENU_VideoTrack "Video track"
 #define MSGTR_MENU_Subtitles "Subtitles"
+// mpdvdnav - gui
+#define MSGTR_MENU_DVDNAV "DVDNAV"
+#define MSGTR_MENU_PlayDVDNAV "Play DVDNAV..."
+#define MSGTR_MENU_MenuDVDNAV "Main DVD Menu"
 
 // --- equalizer
 // Note: If you change MSGTR_EQU_Audio please see if it still fits MSGTR_PREFERENCES_Audio
--- libmpcodecs/vf_expand.c	2007-10-07 21:49:25.000000000 +0200
+++ libmpcodecs/vf_expand.c	2007-10-08 21:09:26.000000000 +0200
@@ -96,7 +96,7 @@
     }
 }
 
-static void draw_func(int x0,int y0, int w,int h,unsigned char* src, unsigned char *srca, int stride){
+static void draw_func(int x0,int y0, int w,int h,int dp,unsigned char* src, unsigned char *srca, int stride){
     unsigned char* dst;
     if(!vo_osd_changed_flag && vf->dmpi->planes[0]==vf->priv->fb_ptr){
 	// ok, enough to update the area inside the video, leave the black bands
@@ -124,19 +124,19 @@
     switch(vf->dmpi->imgfmt){
     case IMGFMT_BGR15:
     case IMGFMT_RGB15:
-	vo_draw_alpha_rgb15(w,h,src,srca,stride,dst,vf->dmpi->stride[0]);
+	vo_draw_alpha_rgb15(w,h,dp,src,srca,stride,dst,vf->dmpi->stride[0]);
 	break;
     case IMGFMT_BGR16:
     case IMGFMT_RGB16:
-	vo_draw_alpha_rgb16(w,h,src,srca,stride,dst,vf->dmpi->stride[0]);
+	vo_draw_alpha_rgb16(w,h,dp,src,srca,stride,dst,vf->dmpi->stride[0]);
 	break;
     case IMGFMT_BGR24:
     case IMGFMT_RGB24:
-	vo_draw_alpha_rgb24(w,h,src,srca,stride,dst,vf->dmpi->stride[0]);
+	vo_draw_alpha_rgb24(w,h,dp,src,srca,stride,dst,vf->dmpi->stride[0]);
 	break;
     case IMGFMT_BGR32:
     case IMGFMT_RGB32:
-	vo_draw_alpha_rgb32(w,h,src,srca,stride,dst,vf->dmpi->stride[0]);
+	vo_draw_alpha_rgb32(w,h,dp,src,srca,stride,dst,vf->dmpi->stride[0]);
 	break;
     case IMGFMT_YV12:
     case IMGFMT_I420:
@@ -145,13 +145,13 @@
     case IMGFMT_IF09:
     case IMGFMT_Y800:
     case IMGFMT_Y8:
-	vo_draw_alpha_yv12(w,h,src,srca,stride,dst,vf->dmpi->stride[0]);
+	vo_draw_alpha_yv12(w,h,dp,src,srca,stride,dst,vf->dmpi->stride[0]);
 	break;
     case IMGFMT_YUY2:
-	vo_draw_alpha_yuy2(w,h,src,srca,stride,dst,vf->dmpi->stride[0]);
+	vo_draw_alpha_yuy2(w,h,dp,src,srca,stride,dst,vf->dmpi->stride[0]);
 	break;
     case IMGFMT_UYVY:
-	vo_draw_alpha_yuy2(w,h,src,srca,stride,dst+1,vf->dmpi->stride[0]);
+	vo_draw_alpha_yuy2(w,h,dp,src,srca,stride,dst+1,vf->dmpi->stride[0]);
 	break;
     }
 }
--- input/input.c	2007-10-07 21:49:26.000000000 +0200
+++ input/input.c	2007-10-23 16:38:47.000000000 +0200
@@ -112,6 +112,8 @@
   { MP_CMD_GET_META_TRACK, "get_meta_track", 0, { {-1,{0}} } },
   { MP_CMD_GET_META_GENRE, "get_meta_genre", 0, { {-1,{0}} } },
   { MP_CMD_SWITCH_AUDIO, "switch_audio", 0, { { MP_CMD_ARG_INT,{-1} }, {-1,{0}} } },
+  { MP_CMD_SWITCH_TITLE, "switch_title", 0, { { MP_CMD_ARG_INT,{-1} }, {-1,{0}} } },
+  { MP_CMD_SWITCH_CHAPTER, "switch_chapter", 0, { { MP_CMD_ARG_INT,{-1} }, {-1,{0}} } },
 #ifdef USE_TV
   { MP_CMD_TV_START_SCAN, "tv_start_scan", 0,  { {-1,{0}} }},
   { MP_CMD_TV_STEP_CHANNEL, "tv_step_channel", 1,  { { MP_CMD_ARG_INT ,{0}}, {-1,{0}} }},
--- input/input.h	2007-10-07 21:49:26.000000000 +0200
+++ input/input.h	2007-10-23 16:30:59.000000000 +0200
@@ -99,6 +99,8 @@
 #define MP_CMD_TV_TELETEXT_ADD_DEC 98
 #define MP_CMD_TV_TELETEXT_GO_LINK 99
 #define MP_CMD_TV_START_SCAN 100
+#define MP_CMD_SWITCH_TITLE 101
+#define MP_CMD_SWITCH_CHAPTER 102
 
 #define MP_CMD_GUI_EVENTS       5000
 #define MP_CMD_GUI_LOADFILE     5001
--- libvo/vo_fbdev.c	2007-10-07 21:49:28.000000000 +0200
+++ libvo/vo_fbdev.c	2007-10-08 21:09:26.000000000 +0200
@@ -558,7 +558,7 @@
 static int fb_line_len;
 static int fb_xres;
 static int fb_yres;
-static void (*draw_alpha_p)(int w, int h, unsigned char *src,
+static void (*draw_alpha_p)(int w, int h, int dp, unsigned char *src,
 		unsigned char *srca, int stride, unsigned char *dst,
 		int dstride);
 
@@ -1049,14 +1049,14 @@
 	return 0;
 }
 
-static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src,
+static void draw_alpha(int x0, int y0, int w, int h, int dp, unsigned char *src,
 		unsigned char *srca, int stride)
 {
 	unsigned char *dst;
 
 	dst = center + fb_line_len * y0 + fb_pixel_size * x0;
 
-	(*draw_alpha_p)(w, h, src, srca, stride, dst, fb_line_len);
+	(*draw_alpha_p)(w, h, dp, src, srca, stride, dst, fb_line_len);
 }
 
 static int draw_frame(uint8_t *src[]) { return 1; }
@@ -1170,6 +1170,13 @@
     return get_image(data);
   case VOCTRL_QUERY_FORMAT:
     return query_format(*((uint32_t*)data));
+  case VOCTRL_YUVSPU_SUPPORT:
+    return VO_FALSE;
+  case VOCTRL_RGBSPU_SUPPORT:
+    return VO_FALSE;
+  case VOCTRL_BGRSPU_SUPPORT:
+    if (fb_bpp == 32 || fb_bpp==24 || fb_bpp==16 || fb_bpp==15) return VO_TRUE;
+    return VO_FALSE;
   }
 
 #ifdef CONFIG_VIDIX
--- libvo/vo_directfb2.c	2007-10-07 21:49:28.000000000 +0200
+++ libvo/vo_directfb2.c	2007-10-08 21:09:26.000000000 +0200
@@ -1442,6 +1442,20 @@
     
 	return(directfb_get_video_eq(data, value));
       }
+    case VOCTRL_YUVSPU_SUPPORT:
+	if (pixel_format==DSPF_I420 || pixel_format==DSPF_YV12) return VO_TRUE;
+	return VO_FALSE;
+    case VOCTRL_RGBSPU_SUPPORT:
+	if (pixel_format==DSPF_RGB32 || pixel_format==DSPF_ARGB || pixel_format==DSPF_RGB24 ||
+		pixel_format==DSPF_RGB16) return VO_TRUE;
+#if DIRECTFBVERSION > 915
+	if (pixel_format==DSPF_ARGB1555) return VO_TRUE;
+#else
+	if (pixel_format==DSPF_RGB15) return VO_TRUE;
+#endif
+	return VO_FALSE;
+    case VOCTRL_BGRSPU_SUPPORT:
+	return VO_FALSE;
   };
   return VO_NOTIMPL;
 }
@@ -1455,7 +1469,7 @@
 
 // hopefully will be removed soon
 
-static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src,
+static void draw_alpha(int x0, int y0, int w, int h, int dp, unsigned char *src,
 		unsigned char *srca, int stride)
 {
         void *dst;
@@ -1474,35 +1488,51 @@
 	switch(pixel_format) {
                 case DSPF_RGB32:
                 case DSPF_ARGB:
-                        vo_draw_alpha_rgb32(w,h,src,srca,stride,((uint8_t *) dst)+pitch*y0 + 4*x0,pitch);
+                        vo_draw_alpha_rgb32(w,h,dp,src,srca,stride,((uint8_t *) dst)+pitch*y0 + 4*x0,pitch);
                         break;
 
                 case DSPF_RGB24:
-                        vo_draw_alpha_rgb24(w,h,src,srca,stride,((uint8_t *) dst)+pitch*y0 + 3*x0,pitch);
+                        vo_draw_alpha_rgb24(w,h,dp,src,srca,stride,((uint8_t *) dst)+pitch*y0 + 3*x0,pitch);
                         break;
 
                 case DSPF_RGB16:
-                        vo_draw_alpha_rgb16(w,h,src,srca,stride,((uint8_t *) dst)+pitch*y0 + 2*x0,pitch);
+                        vo_draw_alpha_rgb16(w,h,dp,src,srca,stride,((uint8_t *) dst)+pitch*y0 + 2*x0,pitch);
                         break;
 #if DIRECTFBVERSION > DFB_VERSION(0,9,15)
                 case DSPF_ARGB1555:
 #else
                 case DSPF_RGB15:
 #endif
-                        vo_draw_alpha_rgb15(w,h,src,srca,stride,((uint8_t *) dst)+pitch*y0 + 2*x0,pitch);
+                        vo_draw_alpha_rgb15(w,h,dp,src,srca,stride,((uint8_t *) dst)+pitch*y0 + 2*x0,pitch);
                         break;
 
 		case DSPF_YUY2:
-    			vo_draw_alpha_yuy2(w,h,src,srca,stride,((uint8_t *) dst) + pitch*y0 + 2*x0,pitch);
+    			vo_draw_alpha_yuy2(w,h,dp,src,srca,stride,((uint8_t *) dst) + pitch*y0 + 2*x0,pitch);
 		break;
 
         	case DSPF_UYVY:
-    			vo_draw_alpha_yuy2(w,h,src,srca,stride,((uint8_t *) dst) + pitch*y0 + 2*x0 + 1,pitch);
+    			vo_draw_alpha_yuy2(w,h,dp,src,srca,stride,((uint8_t *) dst) + pitch*y0 + 2*x0 + 1,pitch);
 		break;
 
         	case DSPF_I420:
 		case DSPF_YV12:
-    			vo_draw_alpha_yv12(w,h,src,srca,stride,((uint8_t *) dst) + pitch*y0 + 1*x0,pitch);
+ 		  switch (dp) {
+ 		    case DEST_PLANES_Y:
+ 			vo_draw_alpha_yv12(w,h,dp,src,srca,stride,((uint8_t *) dst) + pitch*y0 + 1*x0,pitch);
+ 			break;
+ 		    case DEST_PLANES_U:
+ 			if (pixel_format==DSPF_YV12)
+ 			    vo_draw_alpha_yv12(w,h,dp,src,srca,stride,((uint8_t *) dst) + pitch*height/4 + pitch*y0 + 1*x0,pitch);
+ 			    else
+ 			    vo_draw_alpha_yv12(w,h,dp,src,srca,stride,((uint8_t *) dst) + pitch*height/2 + pitch*y0 + 1*x0,pitch);
+ 		        break;
+ 		    case DEST_PLANES_V:
+ 			if (pixel_format==DSPF_YV12)
+ 			    vo_draw_alpha_yv12(w,h,dp,src,srca,stride,((uint8_t *) dst) + pitch*height/2 + pitch*y0 + 1*x0,pitch);
+ 			    else
+ 			    vo_draw_alpha_yv12(w,h,dp,src,srca,stride,((uint8_t *) dst) + pitch*height/4 + pitch*y0 + 1*x0,pitch);
+ 		        break;
+ 		    }
 		break;
 		}
 
--- libvo/vo_vesa.c	2007-10-07 21:49:28.000000000 +0200
+++ libvo/vo_vesa.c	2007-10-08 21:09:26.000000000 +0200
@@ -47,6 +47,7 @@
 #include "vosub_vidix.h"
 #endif
 #include "mp_msg.h"
+#include "help_mp.h"
 
 #include "libswscale/swscale.h"
 #include "libmpcodecs/vf_scale.h"
@@ -108,7 +109,7 @@
 static unsigned video_mode; /* selected video mode for playback */
 static struct VesaModeInfoBlock video_mode_info;
 static int flip_trigger = 0;
-static void (*draw_alpha_fnc)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride);
+static void (*draw_alpha_fnc)(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride);
 
 /* multibuffering */
 uint8_t*  video_base; /* should be never changed */
@@ -296,7 +297,7 @@
 /* Please comment it out if you want have OSD within movie */
 /*#define OSD_OUTSIDE_MOVIE 1*/
 
-static void draw_alpha_32(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)
+static void draw_alpha_32(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride)
 {
    int dstride=HAS_DGA()?video_mode_info.XResolution:dstW;
 #ifndef OSD_OUTSIDE_MOVIE
@@ -306,10 +307,10 @@
 	y0 += y_offset;
    }
 #endif
-   vo_draw_alpha_rgb32(w,h,src,srca,stride,dga_buffer+4*(y0*dstride+x0),4*dstride);
+   vo_draw_alpha_rgb32(w,h,dp,src,srca,stride,dga_buffer+4*(y0*dstride+x0),4*dstride);
 }
 
-static void draw_alpha_24(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)
+static void draw_alpha_24(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride)
 {
    int dstride=HAS_DGA()?video_mode_info.XResolution:dstW;
 #ifndef OSD_OUTSIDE_MOVIE
@@ -319,10 +320,10 @@
 	y0 += y_offset;
    }
 #endif
-   vo_draw_alpha_rgb24(w,h,src,srca,stride,dga_buffer+3*(y0*dstride+x0),3*dstride);
+   vo_draw_alpha_rgb24(w,h,dp,src,srca,stride,dga_buffer+3*(y0*dstride+x0),3*dstride);
 }
 
-static void draw_alpha_16(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)
+static void draw_alpha_16(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride)
 {
    int dstride=HAS_DGA()?video_mode_info.XResolution:dstW;
 #ifndef OSD_OUTSIDE_MOVIE
@@ -332,10 +333,10 @@
 	y0 += y_offset;
    }
 #endif
-   vo_draw_alpha_rgb16(w,h,src,srca,stride,dga_buffer+2*(y0*dstride+x0),2*dstride);
+   vo_draw_alpha_rgb16(w,h,dp,src,srca,stride,dga_buffer+2*(y0*dstride+x0),2*dstride);
 }
 
-static void draw_alpha_15(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)
+static void draw_alpha_15(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride)
 {
    int dstride=HAS_DGA()?video_mode_info.XResolution:dstW;
 #ifndef OSD_OUTSIDE_MOVIE
@@ -345,15 +346,16 @@
 	y0 += y_offset;
    }
 #endif
-   vo_draw_alpha_rgb15(w,h,src,srca,stride,dga_buffer+2*(y0*dstride+x0),2*dstride);
+   vo_draw_alpha_rgb15(w,h,dp,src,srca,stride,dga_buffer+2*(y0*dstride+x0),2*dstride);
 }
 
-static void draw_alpha_null(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)
+static void draw_alpha_null(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride)
 {
   UNUSED(x0);
   UNUSED(y0);
   UNUSED(w);
   UNUSED(h);
+  UNUSED(dp);
   UNUSED(src);
   UNUSED(srca);
   UNUSED(stride);
@@ -1103,6 +1105,14 @@
   switch (request) {
   case VOCTRL_QUERY_FORMAT:
     return query_format(*((uint32_t*)data));
+  case VOCTRL_YUVSPU_SUPPORT:
+    return VO_FALSE;
+  case VOCTRL_RGBSPU_SUPPORT:
+    return VO_FALSE;
+  case VOCTRL_BGRSPU_SUPPORT:
+    if (dstFourcc == IMGFMT_BGR15 || dstFourcc == IMGFMT_BGR16 || dstFourcc == IMGFMT_BGR24 ||
+	    dstFourcc == IMGFMT_BGR32 || dstFourcc == IMGFMT_BGR16) return VO_TRUE;
+    return VO_FALSE;
   }
 
 #ifdef CONFIG_VIDIX
--- libvo/osd.c	2007-10-07 21:49:28.000000000 +0200
+++ libvo/osd.c	2007-10-08 21:09:26.000000000 +0200
@@ -11,8 +11,9 @@
 #include <inttypes.h>
 #include "cpudetect.h"
 #include "mangle.h"
+#include "video_out.h"
 
-#ifdef ARCH_X86
+#if defined(ARCH_X86) || defined(ARCH_X86_64)
 #define CAN_COMPILE_X86_ASM
 #endif
 
@@ -101,152 +102,152 @@
 
 #endif //CAN_COMPILE_X86_ASM
 
-void vo_draw_alpha_yv12(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
+void vo_draw_alpha_yv12(int w,int h, int dp, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
 #ifdef RUNTIME_CPUDETECT
 #ifdef CAN_COMPILE_X86_ASM
 	// ordered by speed / fastest first
 	if(gCpuCaps.hasMMX2)
-		vo_draw_alpha_yv12_MMX2(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_yv12_MMX2(w, h, dp, src, srca, srcstride, dstbase, dststride);
 	else if(gCpuCaps.has3DNow)
-		vo_draw_alpha_yv12_3DNow(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_yv12_3DNow(w, h, dp, src, srca, srcstride, dstbase, dststride);
 	else if(gCpuCaps.hasMMX)
-		vo_draw_alpha_yv12_MMX(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_yv12_MMX(w, h, dp, src, srca, srcstride, dstbase, dststride);
 	else
-		vo_draw_alpha_yv12_X86(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_yv12_X86(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #else
-		vo_draw_alpha_yv12_C(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_yv12_C(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #endif
 #else //RUNTIME_CPUDETECT
 #ifdef HAVE_MMX2
-		vo_draw_alpha_yv12_MMX2(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_yv12_MMX2(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #elif defined (HAVE_3DNOW)
-		vo_draw_alpha_yv12_3DNow(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_yv12_3DNow(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #elif defined (HAVE_MMX)
-		vo_draw_alpha_yv12_MMX(w, h, src, srca, srcstride, dstbase, dststride);
-#elif defined(ARCH_X86)
-		vo_draw_alpha_yv12_X86(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_yv12_MMX(w, h, dp, src, srca, srcstride, dstbase, dststride);
+#elif defined(ARCH_X86) || defined(ARCH_X86_64)
+		vo_draw_alpha_yv12_X86(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #else
-		vo_draw_alpha_yv12_C(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_yv12_C(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #endif
 #endif //!RUNTIME_CPUDETECT
 }
 
-void vo_draw_alpha_yuy2(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
+void vo_draw_alpha_yuy2(int w,int h, int dp, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
 #ifdef RUNTIME_CPUDETECT
 #ifdef CAN_COMPILE_X86_ASM
 	// ordered by speed / fastest first
 	if(gCpuCaps.hasMMX2)
-		vo_draw_alpha_yuy2_MMX2(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_yuy2_MMX2(w, h, dp, src, srca, srcstride, dstbase, dststride);
 	else if(gCpuCaps.has3DNow)
-		vo_draw_alpha_yuy2_3DNow(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_yuy2_3DNow(w, h, dp, src, srca, srcstride, dstbase, dststride);
 	else if(gCpuCaps.hasMMX)
-		vo_draw_alpha_yuy2_MMX(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_yuy2_MMX(w, h, dp, src, srca, srcstride, dstbase, dststride);
 	else
-		vo_draw_alpha_yuy2_X86(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_yuy2_X86(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #else
-		vo_draw_alpha_yuy2_C(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_yuy2_C(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #endif
 #else //RUNTIME_CPUDETECT
 #ifdef HAVE_MMX2
-		vo_draw_alpha_yuy2_MMX2(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_yuy2_MMX2(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #elif defined (HAVE_3DNOW)
-		vo_draw_alpha_yuy2_3DNow(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_yuy2_3DNow(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #elif defined (HAVE_MMX)
-		vo_draw_alpha_yuy2_MMX(w, h, src, srca, srcstride, dstbase, dststride);
-#elif defined(ARCH_X86)
-		vo_draw_alpha_yuy2_X86(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_yuy2_MMX(w, h, dp, src, srca, srcstride, dstbase, dststride);
+#elif defined(ARCH_X86) || defined(ARCH_X86_64)
+		vo_draw_alpha_yuy2_X86(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #else
-		vo_draw_alpha_yuy2_C(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_yuy2_C(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #endif
 #endif //!RUNTIME_CPUDETECT
 }
 
-void vo_draw_alpha_uyvy(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
+void vo_draw_alpha_uyvy(int w,int h, int dp, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
 #ifdef RUNTIME_CPUDETECT
 #ifdef CAN_COMPILE_X86_ASM
 	// ordered by speed / fastest first
 	if(gCpuCaps.hasMMX2)
-		vo_draw_alpha_uyvy_MMX2(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_uyvy_MMX2(w, h, dp, src, srca, srcstride, dstbase, dststride);
 	else if(gCpuCaps.has3DNow)
-		vo_draw_alpha_uyvy_3DNow(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_uyvy_3DNow(w, h, dp, src, srca, srcstride, dstbase, dststride);
 	else if(gCpuCaps.hasMMX)
-		vo_draw_alpha_uyvy_MMX(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_uyvy_MMX(w, h, dp, src, srca, srcstride, dstbase, dststride);
 	else
-		vo_draw_alpha_uyvy_X86(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_uyvy_X86(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #else
-		vo_draw_alpha_uyvy_C(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_uyvy_C(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #endif
 #else //RUNTIME_CPUDETECT
 #ifdef HAVE_MMX2
-		vo_draw_alpha_uyvy_MMX2(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_uyvy_MMX2(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #elif defined (HAVE_3DNOW)
-		vo_draw_alpha_uyvy_3DNow(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_uyvy_3DNow(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #elif defined (HAVE_MMX)
-		vo_draw_alpha_uyvy_MMX(w, h, src, srca, srcstride, dstbase, dststride);
-#elif defined(ARCH_X86)
-		vo_draw_alpha_uyvy_X86(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_uyvy_MMX(w, h, dp, src, srca, srcstride, dstbase, dststride);
+#elif defined(ARCH_X86) || defined(ARCH_X86_64)
+		vo_draw_alpha_uyvy_X86(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #else
-		vo_draw_alpha_uyvy_C(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_uyvy_C(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #endif
 #endif //!RUNTIME_CPUDETECT
 }
 
-void vo_draw_alpha_rgb24(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
+void vo_draw_alpha_rgb24(int w,int h, int dp, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
 #ifdef RUNTIME_CPUDETECT
 #ifdef CAN_COMPILE_X86_ASM
 	// ordered by speed / fastest first
 	if(gCpuCaps.hasMMX2)
-		vo_draw_alpha_rgb24_MMX2(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_rgb24_MMX2(w, h, dp, src, srca, srcstride, dstbase, dststride);
 	else if(gCpuCaps.has3DNow)
-		vo_draw_alpha_rgb24_3DNow(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_rgb24_3DNow(w, h, dp, src, srca, srcstride, dstbase, dststride);
 	else if(gCpuCaps.hasMMX)
-		vo_draw_alpha_rgb24_MMX(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_rgb24_MMX(w, h, dp, src, srca, srcstride, dstbase, dststride);
 	else
-		vo_draw_alpha_rgb24_X86(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_rgb24_X86(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #else
-		vo_draw_alpha_rgb24_C(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_rgb24_C(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #endif
 #else //RUNTIME_CPUDETECT
 #ifdef HAVE_MMX2
-		vo_draw_alpha_rgb24_MMX2(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_rgb24_MMX2(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #elif defined (HAVE_3DNOW)
-		vo_draw_alpha_rgb24_3DNow(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_rgb24_3DNow(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #elif defined (HAVE_MMX)
-		vo_draw_alpha_rgb24_MMX(w, h, src, srca, srcstride, dstbase, dststride);
-#elif defined(ARCH_X86)
-		vo_draw_alpha_rgb24_X86(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_rgb24_MMX(w, h, dp, src, srca, srcstride, dstbase, dststride);
+#elif defined(ARCH_X86) || defined(ARCH_X86_64)
+		vo_draw_alpha_rgb24_X86(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #else
-		vo_draw_alpha_rgb24_C(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_rgb24_C(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #endif
 #endif //!RUNTIME_CPUDETECT
 }
 
-void vo_draw_alpha_rgb32(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
+void vo_draw_alpha_rgb32(int w,int h, int dp, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
 #ifdef RUNTIME_CPUDETECT
 #ifdef CAN_COMPILE_X86_ASM
 	// ordered by speed / fastest first
 	if(gCpuCaps.hasMMX2)
-		vo_draw_alpha_rgb32_MMX2(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_rgb32_MMX2(w, h, dp, src, srca, srcstride, dstbase, dststride);
 	else if(gCpuCaps.has3DNow)
-		vo_draw_alpha_rgb32_3DNow(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_rgb32_3DNow(w, h, dp, src, srca, srcstride, dstbase, dststride);
 	else if(gCpuCaps.hasMMX)
-		vo_draw_alpha_rgb32_MMX(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_rgb32_MMX(w, h, dp, src, srca, srcstride, dstbase, dststride);
 	else
-		vo_draw_alpha_rgb32_X86(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_rgb32_X86(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #else
-		vo_draw_alpha_rgb32_C(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_rgb32_C(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #endif
 #else //RUNTIME_CPUDETECT
 #ifdef HAVE_MMX2
-		vo_draw_alpha_rgb32_MMX2(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_rgb32_MMX2(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #elif defined (HAVE_3DNOW)
-		vo_draw_alpha_rgb32_3DNow(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_rgb32_3DNow(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #elif defined (HAVE_MMX)
-		vo_draw_alpha_rgb32_MMX(w, h, src, srca, srcstride, dstbase, dststride);
-#elif defined(ARCH_X86)
-		vo_draw_alpha_rgb32_X86(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_rgb32_MMX(w, h, dp, src, srca, srcstride, dstbase, dststride);
+#elif defined(ARCH_X86) || defined(ARCH_X86_64)
+		vo_draw_alpha_rgb32_X86(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #else
-		vo_draw_alpha_rgb32_C(w, h, src, srca, srcstride, dstbase, dststride);
+		vo_draw_alpha_rgb32_C(w, h, dp, src, srca, srcstride, dstbase, dststride);
 #endif
 #endif //!RUNTIME_CPUDETECT
 }
@@ -288,7 +289,7 @@
 			mp_msg(MSGT_OSD,MSGL_INFO,"Using MMX (with tiny bit 3DNow) Optimized OnScreenDisplay\n");
 #elif defined (HAVE_MMX)
 			mp_msg(MSGT_OSD,MSGL_INFO,"Using MMX Optimized OnScreenDisplay\n");
-#elif defined(ARCH_X86)
+#elif defined(ARCH_X86) || defined(ARCH_X86_64)
 			mp_msg(MSGT_OSD,MSGL_INFO,"Using X86 Optimized OnScreenDisplay\n");
 #else
 			mp_msg(MSGT_OSD,MSGL_INFO,"Using Unoptimized OnScreenDisplay\n");
@@ -297,8 +298,10 @@
 	}
 }
 
-void vo_draw_alpha_rgb15(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
+void vo_draw_alpha_rgb15(int w,int h, int dp, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
     int y;
+switch (dp) {
+  case DEST_PLANES_Y :
     for(y=0;y<h;y++){
         register unsigned short *dst = (unsigned short*) dstbase;
         register int x;
@@ -327,10 +330,67 @@
         dstbase+=dststride;
     }
     return;
+  case DEST_PLANES_RB:
+    for(y=0;y<h;y++){
+        register unsigned short *dst = (unsigned short*) dstbase;
+        register int x;
+        for(x=0;x<w;x++){
+            if(srca[x]){
+                unsigned char r=dst[x]&0x1F;
+                unsigned char g=(dst[x]>>5)&0x1F;
+                unsigned char b=(dst[x]>>10)&0x1F;
+                r=(((r*srca[x])>>5)+src[x])>>3;
+                dst[x]=(b<<10)|(g<<5)|r;
+            }
+        }
+        src+=srcstride;
+        srca+=srcstride;
+        dstbase+=dststride;
+    }
+    return;
+  case DEST_PLANES_G:
+    for(y=0;y<h;y++){
+        register unsigned short *dst = (unsigned short*) dstbase;
+        register int x;
+        for(x=0;x<w;x++){
+            if(srca[x]){
+                unsigned char r=dst[x]&0x1F;
+                unsigned char g=(dst[x]>>5)&0x1F;
+                unsigned char b=(dst[x]>>10)&0x1F;
+                g=(((g*srca[x])>>5)+src[x])>>3;
+                dst[x]=(b<<10)|(g<<5)|r;
+            }
+        }
+        src+=srcstride;
+        srca+=srcstride;
+        dstbase+=dststride;
+    }
+    return;
+  case DEST_PLANES_BR:
+    for(y=0;y<h;y++){
+        register unsigned short *dst = (unsigned short*) dstbase;
+        register int x;
+        for(x=0;x<w;x++){
+            if(srca[x]){
+                unsigned char r=dst[x]&0x1F;
+                unsigned char g=(dst[x]>>5)&0x1F;
+                unsigned char b=(dst[x]>>10)&0x1F;
+                b=(((b*srca[x])>>5)+src[x])>>3;
+                dst[x]=(b<<10)|(g<<5)|r;
+            }
+        }
+        src+=srcstride;
+        srca+=srcstride;
+        dstbase+=dststride;
+    }
+    return;
+  }
 }
 
-void vo_draw_alpha_rgb16(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
+void vo_draw_alpha_rgb16(int w,int h, int dp, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
     int y;
+switch (dp) {
+  case DEST_PLANES_Y :
     for(y=0;y<h;y++){
         register unsigned short *dst = (unsigned short*) dstbase;
         register int x;
@@ -358,5 +418,60 @@
         dstbase+=dststride;
     }
     return;
+  case DEST_PLANES_RB :
+    for(y=0;y<h;y++){
+        register unsigned short *dst = (unsigned short*) dstbase;
+        register int x;
+        for(x=0;x<w;x++){
+            if(srca[x]){
+                unsigned char r=dst[x]&0x1F;
+                unsigned char b=(dst[x]>>11)&0x1F;
+                unsigned char g=(dst[x]>>5)&0x3F;
+                r=(((r*srca[x])>>5)+src[x])>>3;
+                dst[x]=(b<<11)|(g<<5)|r;
+            }
+        }
+        src+=srcstride;
+        srca+=srcstride;
+        dstbase+=dststride;
+    }
+    return;
+  case DEST_PLANES_G :
+    for(y=0;y<h;y++){
+        register unsigned short *dst = (unsigned short*) dstbase;
+        register int x;
+        for(x=0;x<w;x++){
+            if(srca[x]){
+                unsigned char r=dst[x]&0x1F;
+                unsigned char g=(dst[x]>>5)&0x3F;
+                unsigned char b=(dst[x]>>11)&0x1F;
+                g=(((g*srca[x])>>6)+src[x])>>2;
+                dst[x]=(b<<11)|(g<<5)|r;
+            }
+        }
+        src+=srcstride;
+        srca+=srcstride;
+        dstbase+=dststride;
+    }
+    return;
+  case DEST_PLANES_BR :
+    for(y=0;y<h;y++){
+        register unsigned short *dst = (unsigned short*) dstbase;
+        register int x;
+        for(x=0;x<w;x++){
+            if(srca[x]){
+                unsigned char r=dst[x]&0x1F;
+                unsigned char g=(dst[x]>>5)&0x3F;
+                unsigned char b=(dst[x]>>11)&0x1F;
+                b=(((b*srca[x])>>5)+src[x])>>3;
+                dst[x]=(b<<11)|(g<<5)|r;
+            }
+        }
+        src+=srcstride;
+        srca+=srcstride;
+        dstbase+=dststride;
+    }
+    return;
+  }
 }
 
--- libvo/osd.h	2007-10-07 21:49:28.000000000 +0200
+++ libvo/osd.h	2007-10-08 21:09:26.000000000 +0200
@@ -7,13 +7,13 @@
 
 extern void vo_draw_alpha_init(void); // build tables
 
-extern void vo_draw_alpha_yv12(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride);
-extern void vo_draw_alpha_yuy2(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride);
-extern void vo_draw_alpha_uyvy(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride);
-extern void vo_draw_alpha_rgb24(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride);
-extern void vo_draw_alpha_rgb32(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride);
-extern void vo_draw_alpha_rgb15(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride);
-extern void vo_draw_alpha_rgb16(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride);
+extern void vo_draw_alpha_yv12(int w,int h, int dp, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride);
+extern void vo_draw_alpha_yuy2(int w,int h, int dp, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride);
+extern void vo_draw_alpha_uyvy(int w,int h, int dp, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride);
+extern void vo_draw_alpha_rgb24(int w,int h, int dp, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride);
+extern void vo_draw_alpha_rgb32(int w,int h, int dp, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride);
+extern void vo_draw_alpha_rgb15(int w,int h, int dp, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride);
+extern void vo_draw_alpha_rgb16(int w,int h, int dp, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride);
 
 #endif
 
--- libvo/sub.c	2007-10-07 21:49:28.000000000 +0200
+++ libvo/sub.c	2007-10-08 21:09:26.000000000 +0200
@@ -154,11 +154,12 @@
 }
 
 // renders the buffer
-inline static void vo_draw_text_from_buffer(mp_osd_obj_t* obj,void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)){
+inline static void vo_draw_text_from_buffer(mp_osd_obj_t* obj,void (*draw_alpha)(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride)){
     if (obj->allocated > 0) {
 	draw_alpha(obj->bbox.x1,obj->bbox.y1,
 		   obj->bbox.x2-obj->bbox.x1,
 		   obj->bbox.y2-obj->bbox.y1,
+		   DEST_PLANES_Y,
 		   obj->bitmap_buffer,
 		   obj->alpha_buffer,
 		   obj->stride);
@@ -1022,7 +1023,7 @@
   obj->flags |= OSDFLAG_BBOX;
 }
 
-inline static void vo_draw_spudec_sub(mp_osd_obj_t* obj, void (*draw_alpha)(int x0, int y0, int w, int h, unsigned char* src, unsigned char* srca, int stride))
+inline static void vo_draw_spudec_sub(mp_osd_obj_t* obj, void (*draw_alpha)(int x0, int y0, int w, int h, int dp, unsigned char* src, unsigned char* srca, int stride))
 {
   spudec_draw_scaled(vo_spudec, obj->dxs, obj->dys, draw_alpha);
 }
@@ -1223,7 +1224,7 @@
     }
 }
 
-void vo_draw_text(int dxs,int dys,void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)){
+void vo_draw_text(int dxs,int dys,void (*draw_alpha)(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride)){
     mp_osd_obj_t* obj=vo_osd_list;
     vo_update_osd(dxs,dys);
     while(obj){
--- libvo/sub.h	2007-10-07 21:49:28.000000000 +0200
+++ libvo/sub.h	2007-10-08 21:09:26.000000000 +0200
@@ -120,7 +120,7 @@
 //extern void vo_draw_text_osd(int dxs,int dys,void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride));
 //extern void vo_draw_text_progbar(int dxs,int dys,void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride));
 //extern void vo_draw_text_sub(int dxs,int dys,void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride));
-extern void vo_draw_text(int dxs,int dys,void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride));
+extern void vo_draw_text(int dxs,int dys,void (*draw_alpha)(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride));
 extern void vo_remove_text(int dxs,int dys,void (*remove)(int x0,int y0, int w,int h));
 
 void vo_init_osd(void);
--- libvo/vo_xvmc.c	2007-10-07 21:49:28.000000000 +0200
+++ libvo/vo_xvmc.c	2007-10-08 21:09:26.000000000 +0200
@@ -93,12 +93,12 @@
 static int free_element;
 
 
-static void (*draw_osd_fnc)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride);
+static void (*draw_osd_fnc)(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride);
 static void (*clear_osd_fnc)(int x0,int y0, int w,int h);
 static void (*init_osd_fnc)(void);
 
-static void   draw_osd_AI44(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride);
-static void   draw_osd_IA44(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride);
+static void   draw_osd_AI44(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride);
+static void   draw_osd_IA44(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride);
 static void   clear_osd_subpic(int x0,int y0, int w,int h);
 static void   init_osd_yuv_pal(void);
 
@@ -854,7 +854,7 @@
    subpicture_alloc = 1;
 }
 
-static void draw_osd_IA44(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
+static void draw_osd_IA44(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride){
 int ox,oy;
 int rez;
 
@@ -874,7 +874,7 @@
    }
 }
 
-static void draw_osd_AI44(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
+static void draw_osd_AI44(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride){
 int ox,oy;
 int rez;
    if(  mp_msg_test(MSGT_VO,MSGL_DBG4) )
--- libvo/vo_dfbmga.c	2007-10-07 21:49:28.000000000 +0200
+++ libvo/vo_dfbmga.c	2007-10-08 21:09:26.000000000 +0200
@@ -925,7 +925,7 @@
 }
 
 static void
-vo_draw_alpha_alut44( int w, int h,
+vo_draw_alpha_alut44( int w, int h, int dp,
                     unsigned char* src,
                     unsigned char *srca,
                     int srcstride,
@@ -956,6 +956,7 @@
 static void
 draw_alpha( int x0, int y0,
             int w, int h,
+	    int dp,
             unsigned char *src,
 	    unsigned char *srca,
             int stride )
@@ -980,38 +981,47 @@
 
      switch (subframe_format) {
      case DSPF_ALUT44:
-          vo_draw_alpha_alut44( w, h, src, srca, stride,
+          vo_draw_alpha_alut44( w, h, dp, src, srca, stride,
                                 ((uint8_t *) dst) + pitch * y0 + x0,
                               pitch );
           break;
      case DSPF_RGB32:
      case DSPF_ARGB:
-	  vo_draw_alpha_rgb32( w, h, src, srca, stride,
+	  vo_draw_alpha_rgb32( w, h, dp, src, srca, stride,
 			       (( uint8_t *) dst) + pitch * y0 + 4 * x0,
                                pitch );
 	  break;
      case DSPF_RGB24:
-	  vo_draw_alpha_rgb24( w, h, src, srca, stride,
+	  vo_draw_alpha_rgb24( w, h, dp, src, srca, stride,
 			       ((uint8_t *) dst) + pitch * y0 + 3 * x0,
                                pitch );
 	  break;
      case DSPF_RGB16:
-	  vo_draw_alpha_rgb16( w, h, src, srca, stride,
+	  vo_draw_alpha_rgb16( w, h, dp, src, srca, stride,
 			       ((uint8_t *) dst) + pitch * y0 + 2 * x0,
                                pitch );
 	  break;
      case DSPF_ARGB1555:
-	  vo_draw_alpha_rgb15( w, h, src, srca, stride,
+	  vo_draw_alpha_rgb15( w, h, dp, src, srca, stride,
 			       ((uint8_t *) dst) + pitch * y0 + 2 * x0,
                                pitch );
 	  break;
      case DSPF_YUY2:
-	  vo_draw_alpha_yuy2( w, h, src, srca, stride,
+	switch (dp) {
+	    case DEST_PLANES_Y:
+	    vo_draw_alpha_yuy2( w, h, dp, src, srca, stride,
 			      ((uint8_t *) dst) + pitch * y0 + 2 * x0,
                               pitch );
 	  break;
+	    case DEST_PLANES_YUYV:
+	    vo_draw_alpha_yv12( w, h, dp, src, srca, stride,
+			      ((uint8_t *) dst) + pitch * y0 + 2 * x0,
+                              pitch );
+	    break;
+	    }
+	  break;
      case DSPF_UYVY:
-	  vo_draw_alpha_yuy2( w, h, src, srca, stride,
+	  vo_draw_alpha_yuy2( w, h, dp, src, srca, stride,
 			      ((uint8_t *) dst) + pitch * y0 + 2 * x0 + 1,
                               pitch );
 	  break;
@@ -1021,10 +1031,34 @@
 #endif
      case DSPF_I420:
      case DSPF_YV12:
-	  vo_draw_alpha_yv12( w, h, src, srca, stride,
+	switch (dp) {
+	  case DEST_PLANES_Y:
+	    vo_draw_alpha_yv12( w, h, dp, src, srca, stride,
 			      ((uint8_t *) dst) + pitch * y0 + x0,
                               pitch );
 	  break;
+	  case DEST_PLANES_U:
+	    if (subframe_format==DSPF_YV12)
+		vo_draw_alpha_yv12( w, h, dp, src, srca, stride,
+			      ((uint8_t *) dst) + pitch * y0 + x0 + pitch * in_height,
+                              pitch );
+		else
+		vo_draw_alpha_yv12( w, h, dp, src, srca, stride,
+			      ((uint8_t *) dst) + pitch * y0 + x0 + pitch * (in_height+in_height/2),
+                              pitch );
+	    break;
+	  case DEST_PLANES_V:
+	    if (subframe_format==DSPF_YV12)
+		vo_draw_alpha_yv12( w, h, dp, src, srca, stride,
+			      ((uint8_t *) dst) + pitch * y0 + x0 + pitch * (in_height+in_height/2),
+                              pitch );
+		else
+		vo_draw_alpha_yv12( w, h, dp, src, srca, stride,
+			      ((uint8_t *) dst) + pitch * y0 + x0 + pitch * in_height,
+                              pitch );
+	    break;
+	  }
+	  break;
      }
 
      subframe->Unlock( subframe );
@@ -1419,6 +1453,18 @@
 
                return get_equalizer( data, value );
           }
+    case VOCTRL_YUVSPU_SUPPORT:
+		if (subframe_format==DSPF_I420 || subframe_format==DSPF_YV12) return VO_TRUE;
+		return VO_FALSE;
+    case VOCTRL_YUYSPU_SUPPORT:
+		if (subframe_format==DSPF_YUY2) return VO_TRUE;
+		return VO_FALSE;
+    case VOCTRL_RGBSPU_SUPPORT:
+		if (subframe_format==DSPF_RGB32 || subframe_format==DSPF_ARGB || subframe_format==DSPF_RGB24 ||
+			subframe_format==DSPF_RGB16 || subframe_format==DSPF_ARGB1555) return VO_TRUE;
+		return VO_FALSE;
+    case VOCTRL_BGRSPU_SUPPORT:
+		return VO_FALSE;
      }
 
      return VO_NOTIMPL;
--- libvo/vo_quartz.c	2007-10-07 21:49:28.000000000 +0200
+++ libvo/vo_quartz.c	2007-10-08 21:12:20.000000000 +0200
@@ -129,7 +129,7 @@
 
 #include "osdep/keycodes.h"
 
-extern void vo_draw_text(int dxs,int dys,void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride));
+extern void vo_draw_text(int dxs,int dys,void (*draw_alpha)(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride));
 
 //PROTOTYPE/////////////////////////////////////////////////////////////////
 static OSStatus KeyEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData);
@@ -194,23 +194,23 @@
     }
 }
 
-static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src, unsigned char *srca, int stride)
+static void draw_alpha(int x0, int y0, int w, int h, int dp, unsigned char *src, unsigned char *srca, int stride)
 {
 	switch (image_format)
 	{
 		case IMGFMT_RGB32:
-			vo_draw_alpha_rgb32(w,h,src,srca,stride,image_data+4*(y0*imgRect.right+x0),4*imgRect.right);
+			vo_draw_alpha_rgb32(w,h,dp,src,srca,stride,image_data+4*(y0*imgRect.right+x0),4*imgRect.right);
 			break;
 		case IMGFMT_YV12:
 		case IMGFMT_IYUV:
 		case IMGFMT_I420:
-			vo_draw_alpha_yv12(w,h,src,srca,stride, ((char*)P) + be2me_32(P->componentInfoY.offset) + x0 + y0 * imgRect.right, imgRect.right);
+			vo_draw_alpha_yv12(w,h,dp,src,srca,stride, ((char*)P) + P->componentInfoY.offset + x0 + y0 * imgRect.right, imgRect.right);
 			break;
 		case IMGFMT_UYVY:
-			vo_draw_alpha_uyvy(w,h,src,srca,stride,((char*)P) + (x0 + y0 * imgRect.right) * 2,imgRect.right*2);
+			vo_draw_alpha_uyvy(w,h,dp,src,srca,stride,((char*)P) + (x0 + y0 * imgRect.right) * 2,imgRect.right*2);
 			break;
 		case IMGFMT_YUY2:
-			vo_draw_alpha_yuy2(w,h,src,srca,stride,((char*)P) + (x0 + y0 * imgRect.right) * 2,imgRect.right*2);
+			vo_draw_alpha_yuy2(w,h,dp,src,srca,stride,((char*)P) + (x0 + y0 * imgRect.right) * 2,imgRect.right*2);
 			break;
 	}
 }
--- libvo/vo_directx.c	2007-10-07 21:49:28.000000000 +0200
+++ libvo/vo_directx.c	2007-10-08 21:12:56.000000000 +0200
@@ -86,7 +86,7 @@
 static BOOL (WINAPI* myGetMonitorInfo)(HMONITOR, LPMONITORINFO) = NULL;
 static RECT last_rect = {0xDEADC0DE, 0xDEADC0DE, 0xDEADC0DE, 0xDEADC0DE};
 
-extern void vo_draw_text(int dxs,int dys,void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride));
+extern void vo_draw_text(int dxs,int dys,void (*draw_alpha)(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride));
 extern int vidmode;
 
 /*****************************************************************************
@@ -144,37 +144,62 @@
 
 LIBVO_EXTERN(directx)
 
-static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src,
+static void draw_alpha(int x0, int y0, int w, int h, int dp, unsigned char *src,
 		unsigned char *srca, int stride)
 {
+    uint8_t *d;
+    uint32_t uvstride=dstride/2;
     switch(image_format) {
     case IMGFMT_YV12 :
     case IMGFMT_I420 :
 	case IMGFMT_IYUV :
 	case IMGFMT_YVU9 :
-    	vo_draw_alpha_yv12(w,h,src,srca,stride,((uint8_t *) image) + dstride*y0 + x0,dstride);
+	    switch (dp) {
+		case DEST_PLANES_Y:
+		    vo_draw_alpha_yv12(w,h,dp,src,srca,stride,((uint8_t *) image) + dstride*y0 + x0,dstride);
+		    break;
+		case DEST_PLANES_U:
+		    if(image_format == IMGFMT_YV12)
+			vo_draw_alpha_yv12(w,h,dp,src,srca,stride,((uint8_t *) image) + image_height*dstride + uvstride*y0 + x0,uvstride);
+			else
+			vo_draw_alpha_yv12(w,h,dp,src,srca,stride,((uint8_t *) image) + image_height*dstride + uvstride*(image_height/2) + uvstride*y0 + x0,uvstride);
+		    break;
+		case DEST_PLANES_V:
+		    if(image_format == IMGFMT_YV12)
+			vo_draw_alpha_yv12(w,h,dp,src,srca,stride,((uint8_t *) image) + image_height*dstride + uvstride*(image_height/2) + uvstride*y0 + x0,uvstride);
+			else
+			vo_draw_alpha_yv12(w,h,dp,src,srca,stride,((uint8_t *) image) + image_height*dstride + uvstride*y0 + x0,uvstride);
+		    break;
+		}
 	break;
 	case IMGFMT_YUY2 :
-	    vo_draw_alpha_yuy2(w,h,src,srca,stride,((uint8_t *) image)+ dstride*y0 + 2*x0 ,dstride);
+	    switch (dp) {
+		case DEST_PLANES_Y:
+		    vo_draw_alpha_yuy2(w,h,dp,src,srca,stride,((uint8_t *) image)+ dstride*y0 + 2*x0 ,dstride);
+		    break;
+		case DEST_PLANES_YUYV:
+		    vo_draw_alpha_yv12(w,h,dp,src,srca,stride,((uint8_t *) image)+ dstride*y0 + 2*x0 ,dstride);
+		    break;
+		}
     break;
     case IMGFMT_UYVY :
-        vo_draw_alpha_yuy2(w,h,src,srca,stride,((uint8_t *) image) + dstride*y0 + 2*x0 + 1,dstride);
+	vo_draw_alpha_yuy2(w,h,dp,src,srca,stride,((uint8_t *) image) + dstride*y0 + 2*x0 + 1,dstride);
     break;
 	case IMGFMT_RGB15:	
     case IMGFMT_BGR15:
-		vo_draw_alpha_rgb15(w,h,src,srca,stride,((uint8_t *) image)+dstride*y0+2*x0,dstride);
+		vo_draw_alpha_rgb15(w,h,dp,src,srca,stride,((uint8_t *) image)+dstride*y0+2*x0,dstride);
     break;
     case IMGFMT_RGB16:
 	case IMGFMT_BGR16:
-        vo_draw_alpha_rgb16(w,h,src,srca,stride,((uint8_t *) image)+dstride*y0+2*x0,dstride);
+	vo_draw_alpha_rgb16(w,h,dp,src,srca,stride,((uint8_t *) image)+dstride*y0+2*x0,dstride);
     break;
     case IMGFMT_RGB24:
 	case IMGFMT_BGR24:
-        vo_draw_alpha_rgb24(w,h,src,srca,stride,((uint8_t *) image)+dstride*y0+4*x0,dstride);
+        vo_draw_alpha_rgb24(w,h,dp,src,srca,stride,((uint8_t *) image)+dstride*y0+4*x0,dstride);
     break;
     case IMGFMT_RGB32:
 	case IMGFMT_BGR32:
-        vo_draw_alpha_rgb32(w,h,src,srca,stride,((uint8_t *) image)+dstride*y0+4*x0,dstride);
+        vo_draw_alpha_rgb32(w,h,dp,src,srca,stride,((uint8_t *) image)+dstride*y0+4*x0,dstride);
     break;
     }
 }
@@ -1576,6 +1601,25 @@
         }
         aspect_save_screenres(vo_screenwidth, vo_screenheight);
         return VO_TRUE;
+	case VOCTRL_YUVSPU_SUPPORT: {
+		if (image_format==IMGFMT_YV12 || image_format==IMGFMT_I420 ||
+		    image_format==IMGFMT_IYUV || image_format==IMGFMT_YVU9) return VO_TRUE;
+		return VO_FALSE;
+	}
+	case VOCTRL_YUYSPU_SUPPORT: {
+		if (image_format==IMGFMT_YUY2) return VO_TRUE;
+		return VO_FALSE;
+	}
+	case VOCTRL_RGBSPU_SUPPORT: {
+		if (image_format==IMGFMT_RGB15 || image_format==IMGFMT_RGB16 ||
+		    image_format==IMGFMT_RGB32) return VO_TRUE;
+		return VO_FALSE;
+	}
+	case VOCTRL_BGRSPU_SUPPORT: {
+		if (image_format==IMGFMT_BGR15 || image_format==IMGFMT_BGR16 ||
+		    image_format==IMGFMT_BGR32) return VO_TRUE;
+		return VO_FALSE;
+	}
     case VOCTRL_RESET:
         last_rect.left = 0xDEADC0DE;   // reset window position cache
         // fall-through intended
--- libvo/osd_template.c	2007-10-07 21:49:28.000000000 +0200
+++ libvo/osd_template.c	2007-10-08 21:09:26.000000000 +0200
@@ -27,7 +27,7 @@
 #define EMMS     "emms"
 #endif
 
-static inline void RENAME(vo_draw_alpha_yv12)(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
+static inline void RENAME(vo_draw_alpha_yv12)(int w,int h, int dp, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
     int y;
 #if defined(FAST_OSD) && !defined(HAVE_MMX)
     w=w>>1;
@@ -97,7 +97,7 @@
     return;
 }
 
-static inline void RENAME(vo_draw_alpha_yuy2)(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
+static inline void RENAME(vo_draw_alpha_yuy2)(int w,int h, int dp, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
     int y;
 #if defined(FAST_OSD) && !defined(HAVE_MMX)
     w=w>>1;
@@ -169,7 +169,7 @@
     return;
 }
 
-static inline void RENAME(vo_draw_alpha_uyvy)(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
+static inline void RENAME(vo_draw_alpha_uyvy)(int w,int h, int dp, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
   int y;
 #if defined(FAST_OSD)
   w=w>>1;
@@ -193,8 +193,10 @@
   }
 }
 
-static inline void RENAME(vo_draw_alpha_rgb24)(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
+static inline void RENAME(vo_draw_alpha_rgb24)(int w,int h, int dp, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
     int y;
+switch (dp) {
+ case DEST_PLANES_Y:
 #ifdef HAVE_MMX
     asm volatile(
         "pxor %%mm7, %%mm7\n\t"
@@ -299,13 +301,61 @@
 	asm volatile(EMMS:::"memory");
 #endif
     return;
+ case DEST_PLANES_RB:
+ for(y=0;y<h;y++){
+     register unsigned char *dst = dstbase;
+     register int x;
+     for(x=0;x<w;x++){
+         if(srca[x]){
+		dst[0]=((dst[0]*srca[x])>>8)+src[x];
+         }
+         dst+=3; // 24bpp
+     }
+     src+=srcstride;
+     srca+=srcstride;
+     dstbase+=dststride;
+ }
+ return;
+ case DEST_PLANES_G:
+ for(y=0;y<h;y++){
+     register unsigned char *dst = dstbase;
+     register int x;
+     for(x=0;x<w;x++){
+         if(srca[x]){
+		dst[1]=((dst[1]*srca[x])>>8)+src[x];
+         }
+         dst+=3; // 24bpp
+     }
+     src+=srcstride;
+     srca+=srcstride;
+     dstbase+=dststride;
+ }
+ return;
+ case DEST_PLANES_BR:
+ for(y=0;y<h;y++){
+     register unsigned char *dst = dstbase;
+     register int x;
+     for(x=0;x<w;x++){
+         if(srca[x]){
+		dst[2]=((dst[2]*srca[x])>>8)+src[x];
+         }
+         dst+=3; // 24bpp
+     }
+     src+=srcstride;
+     srca+=srcstride;
+     dstbase+=dststride;
+ }
+ return;
+ }
 }
 
-static inline void RENAME(vo_draw_alpha_rgb32)(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
+static inline void RENAME(vo_draw_alpha_rgb32)(int w,int h, int dp, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride){
     int y;
 #ifdef WORDS_BIGENDIAN
     dstbase++;
 #endif
+switch (dp) {
+ case DEST_PLANES_Y:
 #ifdef HAVE_MMX
 #ifdef HAVE_3DNOW
     asm volatile(
@@ -464,4 +514,44 @@
 	asm volatile(EMMS:::"memory");
 #endif
     return;
+ case DEST_PLANES_RB:
+    for(y=0;y<h;y++){
+        register int x;
+        for(x=0;x<w;x++){
+            if(srca[x]){
+		dstbase[4*x+0]=(((dstbase[4*x+0]*srca[x])>>8)+src[x])&0xff;
+            }
+        }
+        src+=srcstride;
+        srca+=srcstride;
+        dstbase+=dststride;
+    }
+    return;
+ case DEST_PLANES_G:
+    for(y=0;y<h;y++){
+        register int x;
+        for(x=0;x<w;x++){
+            if(srca[x]){
+		dstbase[4*x+1]=(((dstbase[4*x+1]*srca[x])>>8)+src[x])&0xff;
+            }
+        }
+        src+=srcstride;
+        srca+=srcstride;
+        dstbase+=dststride;
+    }
+    return;
+ case DEST_PLANES_BR:
+    for(y=0;y<h;y++){
+        register int x;
+        for(x=0;x<w;x++){
+            if(srca[x]){
+		dstbase[4*x+2]=(((dstbase[4*x+2]*srca[x])>>8)+src[x])&0xff;
+            }
+        }
+        src+=srcstride;
+        srca+=srcstride;
+        dstbase+=dststride;
+    }
+    return;
+ }
 }
--- libvo/vo_yuv4mpeg.c	2007-10-07 21:49:28.000000000 +0200
+++ libvo/vo_yuv4mpeg.c	2007-10-08 21:09:26.000000000 +0200
@@ -181,25 +181,37 @@
 	}
 }
 
-static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src,
+static void draw_alpha(int x0, int y0, int w, int h, int dp, unsigned char *src,
                        unsigned char *srca, int stride) {
 	switch (using_format)
 	{
     	case IMGFMT_YV12:
-	    	vo_draw_alpha_yv12(w, h, src, srca, stride, 
+	    switch (dp) {
+		case DEST_PLANES_Y:
+		    vo_draw_alpha_yv12(w, h, dp, src, srca, stride,
 				       image + y0 * image_width + x0, image_width);
 			break;
+		case DEST_PLANES_U:
+		    if (image_u) vo_draw_alpha_yv12(w, h, dp, src, srca, stride,
+				image_u + y0 * image_width + x0, image_width);
+		    break;
+		case DEST_PLANES_V:
+		    if (image_v) vo_draw_alpha_yv12(w, h, dp, src, srca, stride,
+				image_v + y0 * image_width + x0, image_width);
+		    break;
+		}
+			break;
 		
 		case IMGFMT_BGR|24:
 		case IMGFMT_RGB|24:
 			if (config_interlace != Y4M_ILACE_BOTTOM_FIRST)
-				vo_draw_alpha_rgb24(w, h, src, srca, stride,
+				vo_draw_alpha_rgb24(w, h, dp, src, srca, stride,
 						rgb_buffer + (y0 * image_width + x0) * 3, image_width * 3);
 			else
 			{
 				swap_fields (rgb_buffer, image_height, image_width * 3);
 
-				vo_draw_alpha_rgb24(w, h, src, srca, stride,
+				vo_draw_alpha_rgb24(w, h, dp, src, srca, stride,
 						rgb_buffer + (y0 * image_width  + x0) * 3, image_width * 3);
 				
 				swap_fields (rgb_buffer, image_height, image_width * 3);
@@ -545,6 +557,15 @@
     return query_format(*((uint32_t*)data));
   case VOCTRL_DUPLICATE_FRAME:
     return write_last_frame();
+  case VOCTRL_YUVSPU_SUPPORT:
+    if (using_format==IMGFMT_YV12) return VO_TRUE;
+    return VO_FALSE;
+  case VOCTRL_RGBSPU_SUPPORT:
+    if (using_format==IMGFMT_RGB|24) return VO_TRUE;
+    return VO_FALSE;
+  case VOCTRL_BGRSPU_SUPPORT:
+    if (using_format==IMGFMT_BGR|24) return VO_TRUE;
+    return VO_FALSE;
   }
   return VO_NOTIMPL;
 }
--- libvo/video_out.h	2007-10-07 21:49:28.000000000 +0200
+++ libvo/video_out.h	2007-10-08 21:09:26.000000000 +0200
@@ -85,6 +85,15 @@
   int w,h;
 } mp_win_t;
 
+// Current vo is YUV mode
+#define VOCTRL_YUVSPU_SUPPORT 33
+// Current vo is RGB mode
+#define VOCTRL_RGBSPU_SUPPORT 34
+// Current vo is BGR mode
+#define VOCTRL_BGRSPU_SUPPORT 35
+// Current vo is YUY mode
+#define VOCTRL_YUYSPU_SUPPORT 36
+
 #define VO_TRUE		1
 #define VO_FALSE	0
 #define VO_ERROR	-1
@@ -97,6 +106,15 @@
 #define VOFLAG_FLIPPING		0x08
 #define VOFLAG_XOVERLAY_SUB_VO  0x10000
 
+// dest planes (draw_alpha)
+#define	DEST_PLANES_Y		0	// Y planes (default)
+#define DEST_PLANES_U		1	// U planes in YUV mode
+#define DEST_PLANES_V		2	// V planes in YUV mode
+#define DEST_PLANES_RB		3	// R or B planes in RGB or BGR mode
+#define DEST_PLANES_G		4	// G planes in RGB or BGR mode
+#define DEST_PLANES_BR		5	// B or R planes in RGB or BGR mode
+#define DEST_PLANES_YUYV	6	// Yuv (all) planes in YUYv mode
+
 typedef struct vo_info_s
 {
         /* driver name ("Matrox Millennium G200/G400" */
--- libvo/vosub_vidix.c	2007-10-07 21:49:28.000000000 +0200
+++ libvo/vosub_vidix.c	2007-10-08 21:09:26.000000000 +0200
@@ -276,7 +276,7 @@
   }	
 }
 
-static void draw_alpha(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)
+static void draw_alpha(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride)
 {
     uint32_t apitch,bespitch;
     void *lvo_mem;
@@ -290,36 +290,57 @@
     case IMGFMT_IF09:
     case IMGFMT_Y8:
     case IMGFMT_Y800:
+	switch (dp) {
+	  case DEST_PLANES_Y:
 	bespitch = (vidix_play.src.w + apitch) & (~apitch);
-        vo_draw_alpha_yv12(w,h,src,srca,stride,lvo_mem+bespitch*y0+x0,bespitch);
+           vo_draw_alpha_yv12(w,h,dp,src,srca,stride,lvo_mem+bespitch*y0+x0,bespitch);
+	  break;
+	  case DEST_PLANES_U:
+	     lvo_mem = vidix_mem + vidix_play.offsets[next_frame] + vidix_play.offset.u;
+	     lvo_mem += dstrides.u*y0/2 + x0;
+	     vo_draw_alpha_yv12(w,h,dp,src,srca,stride,lvo_mem,dstrides.u/2);
+	  break;
+	  case DEST_PLANES_V:
+	     lvo_mem = vidix_mem + vidix_play.offsets[next_frame] + vidix_play.offset.v;
+	     lvo_mem += dstrides.v*y0/2 + x0;
+	     vo_draw_alpha_yv12(w,h,dp,src,srca,stride,lvo_mem,dstrides.v/2);
+	  break;
+	  }
         break;
     case IMGFMT_YUY2:
 	bespitch = (vidix_play.src.w*2 + apitch) & (~apitch);
-        vo_draw_alpha_yuy2(w,h,src,srca,stride,lvo_mem+bespitch*y0+2*x0,bespitch);
+	switch (dp) {
+	case DEST_PLANES_Y:
+          vo_draw_alpha_yuy2(w,h,dp,src,srca,stride,lvo_mem+bespitch*y0+2*x0,bespitch);
+	  break;
+	case DEST_PLANES_YUYV:
+           vo_draw_alpha_yv12(w,h,dp,src,srca,stride,lvo_mem+bespitch*y0+x0,bespitch);
+	  break;
+	  }
         break;
     case IMGFMT_UYVY:
 	bespitch = (vidix_play.src.w*2 + apitch) & (~apitch);
-        vo_draw_alpha_yuy2(w,h,src,srca,stride,lvo_mem+bespitch*y0+2*x0+1,bespitch);
+        vo_draw_alpha_yuy2(w,h,dp,src,srca,stride,lvo_mem+bespitch*y0+2*x0+1,bespitch);
         break;
     case IMGFMT_RGB32:
     case IMGFMT_BGR32:
 	bespitch = (vidix_play.src.w*4 + apitch) & (~apitch);
-	vo_draw_alpha_rgb32(w,h,src,srca,stride,lvo_mem+y0*bespitch+4*x0,bespitch);
+	vo_draw_alpha_rgb32(w,h,dp,src,srca,stride,lvo_mem+y0*bespitch+4*x0,bespitch);
         break;
     case IMGFMT_RGB24:
     case IMGFMT_BGR24:
 	bespitch = (vidix_play.src.w*3 + apitch) & (~apitch);
-	vo_draw_alpha_rgb24(w,h,src,srca,stride,lvo_mem+y0*bespitch+3*x0,bespitch);
+	vo_draw_alpha_rgb24(w,h,dp,src,srca,stride,lvo_mem+y0*bespitch+3*x0,bespitch);
         break;
     case IMGFMT_RGB16:
     case IMGFMT_BGR16:
 	bespitch = (vidix_play.src.w*2 + apitch) & (~apitch);
-	vo_draw_alpha_rgb16(w,h,src,srca,stride,lvo_mem+y0*bespitch+2*x0,bespitch);
+	vo_draw_alpha_rgb16(w,h,dp,src,srca,stride,lvo_mem+y0*bespitch+2*x0,bespitch);
         break;
     case IMGFMT_RGB15:
     case IMGFMT_BGR15:
 	bespitch = (vidix_play.src.w*2 + apitch) & (~apitch);
-	vo_draw_alpha_rgb15(w,h,src,srca,stride,lvo_mem+y0*bespitch+2*x0,bespitch);
+	vo_draw_alpha_rgb15(w,h,dp,src,srca,stride,lvo_mem+y0*bespitch+2*x0,bespitch);
         break;
     default:
 	return;
@@ -505,7 +526,7 @@
 	    next_frame = i;
 	    memset(vidix_mem + vidix_play.offsets[i], 0x80,
 		vidix_play.frame_size);
-	    draw_alpha(0, 0, image_width, image_height, tmp, tmpa, image_width);
+	    draw_alpha(0, 0, image_width, image_height, DEST_PLANES_Y, tmp, tmpa, image_width);
 	}
 	free(tmp);
 	free(tmpa);
@@ -693,6 +714,16 @@
 
     return VO_TRUE;
   }
+  case VOCTRL_YUVSPU_SUPPORT:
+    if((vidix_play.fourcc==IMGFMT_YV12 || vidix_play.fourcc==IMGFMT_YV12 || vidix_play.fourcc==IMGFMT_IYUV ||
+	vidix_play.fourcc==IMGFMT_I420 || vidix_play.fourcc==IMGFMT_YVU9 || vidix_play.fourcc==IMGFMT_IF09 ||
+	vidix_play.fourcc==IMGFMT_Y8 || vidix_play.fourcc==IMGFMT_Y800) &&
+	!(vidix_play.flags & VID_PLAY_INTERLEAVED_UV)) return VO_TRUE;
+    return VO_FALSE;
+  case VOCTRL_YUYSPU_SUPPORT:
+    if((vidix_play.fourcc==IMGFMT_YUY2) &&
+	!(vidix_play.flags & VID_PLAY_INTERLEAVED_UV)) return VO_TRUE;
+    return VO_FALSE;
   }
   return VO_NOTIMPL;
   // WARNING: we drop extra parameters (...) here!
--- libvo/vo_dga.c	2007-10-07 21:49:28.000000000 +0200
+++ libvo/vo_dga.c	2007-10-08 21:09:26.000000000 +0200
@@ -227,7 +227,7 @@
 
 //---------------------------------------------------------
 
-static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src,
+static void draw_alpha(int x0, int y0, int w, int h, int dp, unsigned char *src,
                        unsigned char *srca, int stride)
 {
 
@@ -243,19 +243,19 @@
     {
 
         case 32:
-            vo_draw_alpha_rgb32(w, h, src, srca, stride, d + 4 * offset,
+            vo_draw_alpha_rgb32(w, h, dp, src, srca, stride, d + 4 * offset,
                                 4 * buffer_stride);
             break;
         case 24:
-            vo_draw_alpha_rgb24(w, h, src, srca, stride, d + 3 * offset,
+            vo_draw_alpha_rgb24(w, h, dp, src, srca, stride, d + 3 * offset,
                                 3 * buffer_stride);
             break;
         case 15:
-            vo_draw_alpha_rgb15(w, h, src, srca, stride, d + 2 * offset,
+            vo_draw_alpha_rgb15(w, h, dp, src, srca, stride, d + 2 * offset,
                                 2 * buffer_stride);
             break;
         case 16:
-            vo_draw_alpha_rgb16(w, h, src, srca, stride, d + 2 * offset,
+            vo_draw_alpha_rgb16(w, h, dp, src, srca, stride, d + 2 * offset,
                                 2 * buffer_stride);
             break;
     }
@@ -981,6 +981,14 @@
             return get_image(data);
         case VOCTRL_QUERY_FORMAT:
             return query_format(*((uint32_t *) data));
+	case VOCTRL_YUVSPU_SUPPORT:
+	    return VO_FALSE;
+	case VOCTRL_RGBSPU_SUPPORT:
+	    return VO_FALSE;
+	case VOCTRL_BGRSPU_SUPPORT:
+	    if(HW_MODE.vdm_mplayer_depth==32 || HW_MODE.vdm_mplayer_depth==24 ||
+		HW_MODE.vdm_mplayer_depth==15 || HW_MODE.vdm_mplayer_depth==16) return VO_TRUE;
+	    return VO_FALSE;
     }
     return VO_NOTIMPL;
 }
--- libvo/vo_gl2.c	2007-10-07 21:49:28.000000000 +0200
+++ libvo/vo_gl2.c	2007-10-08 21:13:44.000000000 +0200
@@ -84,7 +84,7 @@
 static int      use_glFinish;
 
 static void (*draw_alpha_fnc)
-                 (int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride);
+                 (int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride);
 
 
 /* The squares that are tiled to make up the game screen polygon */
@@ -430,23 +430,23 @@
   glLoadIdentity();
 }
 
-static void draw_alpha_32(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
-   vo_draw_alpha_rgb32(w,h,src,srca,stride,ImageData+4*(y0*image_width+x0),4*image_width);
+static void draw_alpha_32(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride){
+   vo_draw_alpha_rgb32(w,h,dp,src,srca,stride,ImageData+4*(y0*image_width+x0),4*image_width);
 }
 
-static void draw_alpha_24(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
-   vo_draw_alpha_rgb24(w,h,src,srca,stride,ImageData+3*(y0*image_width+x0),3*image_width);
+static void draw_alpha_24(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride){
+   vo_draw_alpha_rgb24(w,h,dp,src,srca,stride,ImageData+3*(y0*image_width+x0),3*image_width);
 }
 
-static void draw_alpha_16(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
-   vo_draw_alpha_rgb16(w,h,src,srca,stride,ImageData+2*(y0*image_width+x0),2*image_width);
+static void draw_alpha_16(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride){
+   vo_draw_alpha_rgb16(w,h,dp,src,srca,stride,ImageData+2*(y0*image_width+x0),2*image_width);
 }
 
-static void draw_alpha_15(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
-   vo_draw_alpha_rgb15(w,h,src,srca,stride,ImageData+2*(y0*image_width+x0),2*image_width);
+static void draw_alpha_15(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride){
+   vo_draw_alpha_rgb15(w,h,dp,src,srca,stride,ImageData+2*(y0*image_width+x0),2*image_width);
 }
 
-static void draw_alpha_null(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
+static void draw_alpha_null(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride){
 }
 
 #ifdef GL_WIN32
@@ -919,6 +919,13 @@
     case VOCTRL_UPDATE_SCREENINFO:
       update_xinerama_info();
       return VO_TRUE;
+    case VOCTRL_YUVSPU_SUPPORT:
+      return VO_FALSE;
+    case VOCTRL_RGBSPU_SUPPORT:
+      return VO_FALSE;
+    case VOCTRL_BGRSPU_SUPPORT:
+      if (image_bpp==15 || image_bpp==16 || image_bpp==24 || image_bpp==32) return VO_TRUE;
+ 	return VO_FALSE;
   }
   return VO_NOTIMPL;
 }
--- libvo/vo_x11.c	2007-10-07 21:49:28.000000000 +0200
+++ libvo/vo_x11.c	2007-10-08 21:09:26.000000000 +0200
@@ -60,7 +60,7 @@
 LIBVO_EXTERN(x11)
 /* private prototypes */
 static void Display_Image(XImage * myximage, unsigned char *ImageData);
-static void (*draw_alpha_fnc) (int x0, int y0, int w, int h,
+static void (*draw_alpha_fnc) (int x0, int y0, int w, int h, int dp,
                                unsigned char *src, unsigned char *srca,
                                int stride);
 
@@ -108,39 +108,39 @@
 
 }
 
-static void draw_alpha_32(int x0, int y0, int w, int h, unsigned char *src,
+static void draw_alpha_32(int x0, int y0, int w, int h, int dp, unsigned char *src,
                           unsigned char *srca, int stride)
 {
-    vo_draw_alpha_rgb32(w, h, src, srca, stride,
+    vo_draw_alpha_rgb32(w, h, dp, src, srca, stride,
                         ImageData + 4 * (y0 * image_width + x0),
                         4 * image_width);
 }
 
-static void draw_alpha_24(int x0, int y0, int w, int h, unsigned char *src,
+static void draw_alpha_24(int x0, int y0, int w, int h, int dp, unsigned char *src,
                           unsigned char *srca, int stride)
 {
-    vo_draw_alpha_rgb24(w, h, src, srca, stride,
+    vo_draw_alpha_rgb24(w, h, dp, src, srca, stride,
                         ImageData + 3 * (y0 * image_width + x0),
                         3 * image_width);
 }
 
-static void draw_alpha_16(int x0, int y0, int w, int h, unsigned char *src,
+static void draw_alpha_16(int x0, int y0, int w, int h, int dp, unsigned char *src,
                           unsigned char *srca, int stride)
 {
-    vo_draw_alpha_rgb16(w, h, src, srca, stride,
+    vo_draw_alpha_rgb16(w, h, dp, src, srca, stride,
                         ImageData + 2 * (y0 * image_width + x0),
                         2 * image_width);
 }
 
-static void draw_alpha_15(int x0, int y0, int w, int h, unsigned char *src,
+static void draw_alpha_15(int x0, int y0, int w, int h, int dp, unsigned char *src,
                           unsigned char *srca, int stride)
 {
-    vo_draw_alpha_rgb15(w, h, src, srca, stride,
+    vo_draw_alpha_rgb15(w, h, dp, src, srca, stride,
                         ImageData + 2 * (y0 * image_width + x0),
                         2 * image_width);
 }
 
-static void draw_alpha_null(int x0, int y0, int w, int h,
+static void draw_alpha_null(int x0, int y0, int w, int h, int dp,
                             unsigned char *src, unsigned char *srca,
                             int stride)
 {
@@ -797,6 +797,14 @@
         case VOCTRL_UPDATE_SCREENINFO:
             update_xinerama_info();
             return VO_TRUE;
+        case VOCTRL_YUVSPU_SUPPORT:
+            return VO_FALSE;
+        case VOCTRL_RGBSPU_SUPPORT:
+	    return VO_FALSE;
+        case VOCTRL_BGRSPU_SUPPORT:
+	    if (out_format == IMGFMT_BGR15 || out_format == IMGFMT_BGR16 ||
+		out_format == IMGFMT_BGR24 || out_format == IMGFMT_BGR32) return VO_TRUE;
+	    return VO_FALSE;
     }
     return VO_NOTIMPL;
 }
--- libvo/vo_sdl.c	2007-10-07 21:49:28.000000000 +0200
+++ libvo/vo_sdl.c	2007-10-08 21:09:26.000000000 +0200
@@ -287,7 +287,7 @@
  *
  **/
 
-static void draw_alpha(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
+static void draw_alpha(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride){
 	struct sdl_priv_s *priv = &sdl_priv;
 	
     if(priv->osd_has_changed) {
@@ -328,16 +328,43 @@
 		case IMGFMT_YV12:  
 		case IMGFMT_I420:
         	case IMGFMT_IYUV:
-            vo_draw_alpha_yv12(w,h,src,srca,stride,((uint8_t *) *(priv->overlay->pixels))+priv->overlay->pitches[0]*y0+x0,priv->overlay->pitches[0]);
+		    switch (dp) {
+			case DEST_PLANES_Y :
+			    vo_draw_alpha_yv12(w,h,dp,src,srca,stride,((uint8_t *) *(priv->overlay->pixels))+priv->overlay->pitches[0]*y0+x0,priv->overlay->pitches[0]);
+			    break;
+			case DEST_PLANES_U :
+			    SDL_OVR_LOCK(-1)
+			    if (priv->format==IMGFMT_YV12)
+				vo_draw_alpha_yv12(w,h,dp,src,srca,stride,((uint8_t *) (priv->overlay->pixels[1]))+priv->overlay->pitches[1]*y0+x0,priv->overlay->pitches[1]);
+				else
+				vo_draw_alpha_yv12(w,h,dp,src,srca,stride,((uint8_t *) (priv->overlay->pixels[2]))+priv->overlay->pitches[2]*y0+x0,priv->overlay->pitches[2]);
+			    SDL_OVR_UNLOCK
+			    break;
+			case DEST_PLANES_V :
+			    SDL_OVR_LOCK(-1)
+			    if (priv->format==IMGFMT_YV12)
+				vo_draw_alpha_yv12(w,h,dp,src,srca,stride,((uint8_t *) (priv->overlay->pixels[2]))+priv->overlay->pitches[2]*y0+x0,priv->overlay->pitches[2]);
+				else
+				vo_draw_alpha_yv12(w,h,dp,src,srca,stride,((uint8_t *) (priv->overlay->pixels[1]))+priv->overlay->pitches[1]*y0+x0,priv->overlay->pitches[1]);
+			    SDL_OVR_UNLOCK
+			    break;
+			}
 		break;
 		case IMGFMT_YUY2:
         	case IMGFMT_YVYU:
                 x0 *= 2;
-    			vo_draw_alpha_yuy2(w,h,src,srca,stride,((uint8_t *) *(priv->overlay->pixels))+priv->overlay->pitches[0]*y0+x0,priv->overlay->pitches[0]);
+		switch (dp) {
+		    case DEST_PLANES_Y :
+			vo_draw_alpha_yuy2(w,h,dp,src,srca,stride,((uint8_t *) *(priv->overlay->pixels))+priv->overlay->pitches[0]*y0+x0,priv->overlay->pitches[0]);
+			break;
+		    case DEST_PLANES_YUYV :
+			vo_draw_alpha_yv12(w,h,dp,src,srca,stride,((uint8_t *) *(priv->overlay->pixels))+priv->overlay->pitches[0]*y0+x0,priv->overlay->pitches[0]);
+			break;
+		    }
 		break;	
         	case IMGFMT_UYVY:
                 x0 *= 2;
-    			vo_draw_alpha_yuy2(w,h,src,srca,stride,((uint8_t *) *(priv->overlay->pixels))+priv->overlay->pitches[0]*y0+x0,priv->overlay->pitches[0]);
+    			vo_draw_alpha_yuy2(w,h,dp,src,srca,stride,((uint8_t *) *(priv->overlay->pixels))+priv->overlay->pitches[0]*y0+x0,priv->overlay->pitches[0]);
 		break;
 
 		default:
@@ -346,19 +373,19 @@
 		switch(priv->format) {
 		case IMGFMT_RGB15:
 		case IMGFMT_BGR15:
-    			vo_draw_alpha_rgb15(w,h,src,srca,stride,((uint8_t *) priv->surface->pixels)+y0*priv->surface->pitch+x0,priv->surface->pitch);
+			vo_draw_alpha_rgb15(w,h,dp,src,srca,stride,((uint8_t *) priv->surface->pixels)+y0*priv->surface->pitch+x0,priv->surface->pitch);
 		break;
 		case IMGFMT_RGB16:
 		case IMGFMT_BGR16:
-    			vo_draw_alpha_rgb16(w,h,src,srca,stride,((uint8_t *) priv->surface->pixels)+y0*priv->surface->pitch+x0,priv->surface->pitch);
+			vo_draw_alpha_rgb16(w,h,dp,src,srca,stride,((uint8_t *) priv->surface->pixels)+y0*priv->surface->pitch+x0,priv->surface->pitch);
 		break;
 		case IMGFMT_RGB24:
 		case IMGFMT_BGR24:
-    			vo_draw_alpha_rgb24(w,h,src,srca,stride,((uint8_t *) priv->surface->pixels)+y0*priv->surface->pitch+x0,priv->surface->pitch);
+			vo_draw_alpha_rgb24(w,h,dp,src,srca,stride,((uint8_t *) priv->surface->pixels)+y0*priv->surface->pitch+x0,priv->surface->pitch);
 		break;
 		case IMGFMT_RGB32:
 		case IMGFMT_BGR32:
-    			vo_draw_alpha_rgb32(w,h,src,srca,stride,((uint8_t *) priv->surface->pixels)+y0*priv->surface->pitch+x0,priv->surface->pitch);
+			vo_draw_alpha_rgb32(w,h,dp,src,srca,stride,((uint8_t *) priv->surface->pixels)+y0*priv->surface->pitch+x0,priv->surface->pitch);
 		break;
 		}
         }
@@ -367,19 +394,19 @@
 		switch(priv->format) {
 		case IMGFMT_RGB15:
 		case IMGFMT_BGR15:
-    			vo_draw_alpha_rgb15(w,h,src,srca,stride,((uint8_t *) priv->rgbsurface->pixels)+y0*priv->rgbsurface->pitch+x0,priv->rgbsurface->pitch);
+			vo_draw_alpha_rgb15(w,h,dp,src,srca,stride,((uint8_t *) priv->rgbsurface->pixels)+y0*priv->rgbsurface->pitch+x0,priv->rgbsurface->pitch);
 		break;
 		case IMGFMT_RGB16:
 		case IMGFMT_BGR16:
-    			vo_draw_alpha_rgb16(w,h,src,srca,stride,((uint8_t *) priv->rgbsurface->pixels)+y0*priv->rgbsurface->pitch+x0,priv->rgbsurface->pitch);
+			vo_draw_alpha_rgb16(w,h,dp,src,srca,stride,((uint8_t *) priv->rgbsurface->pixels)+y0*priv->rgbsurface->pitch+x0,priv->rgbsurface->pitch);
 		break;
 		case IMGFMT_RGB24:
 		case IMGFMT_BGR24:
-    			vo_draw_alpha_rgb24(w,h,src,srca,stride,((uint8_t *) priv->rgbsurface->pixels)+y0*priv->rgbsurface->pitch+x0,priv->rgbsurface->pitch);
+			vo_draw_alpha_rgb24(w,h,dp,src,srca,stride,((uint8_t *) priv->rgbsurface->pixels)+y0*priv->rgbsurface->pitch+x0,priv->rgbsurface->pitch);
 		break;
 		case IMGFMT_RGB32:
 		case IMGFMT_BGR32:
-    			vo_draw_alpha_rgb32(w,h,src,srca,stride,((uint8_t *) priv->rgbsurface->pixels)+y0*priv->rgbsurface->pitch+x0,priv->rgbsurface->pitch);
+			vo_draw_alpha_rgb32(w,h,dp,src,srca,stride,((uint8_t *) priv->rgbsurface->pixels)+y0*priv->rgbsurface->pitch+x0,priv->rgbsurface->pitch);
 		break;
 		}
         }
@@ -1727,6 +1754,18 @@
 	mp_msg(MSGT_VO,MSGL_DBG2, "SDL: Set fullscreen mode\n"); }
     }
     return VO_TRUE;
+  case VOCTRL_YUVSPU_SUPPORT:
+    if (priv->format == IMGFMT_YV12 || priv->format == IMGFMT_I420 || priv->format==IMGFMT_IYUV) return VO_TRUE;
+    return VO_FALSE;
+  case VOCTRL_YUYSPU_SUPPORT:
+    if (priv->format==IMGFMT_YUY2) return VO_TRUE;
+    return VO_FALSE;
+  case VOCTRL_RGBSPU_SUPPORT:
+    if (priv->mode == RGB) return VO_TRUE;
+    return VO_FALSE;
+  case VOCTRL_BGRSPU_SUPPORT:
+    if (priv->mode == BGR) return VO_TRUE;
+    return VO_FALSE;
   }
 
   return VO_NOTIMPL;
--- libvo/vesa_lvo.c	2007-10-07 21:49:28.000000000 +0200
+++ libvo/vesa_lvo.c	2007-10-08 21:09:26.000000000 +0200
@@ -233,50 +233,51 @@
   }	
 }
 
-static void draw_alpha_null(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)
+static void draw_alpha_null(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride)
 {
   UNUSED(x0);
   UNUSED(y0);
   UNUSED(w);
   UNUSED(h);
+  UNUSED(dp);
   UNUSED(src);
   UNUSED(srca);
   UNUSED(stride);
 }
 
-static void draw_alpha(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)
+static void draw_alpha(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride)
 {
     uint32_t bespitch = /*(*/mga_vid_config.src_width;// + 15) & ~15;
     switch(mga_vid_config.format){
     case IMGFMT_BGR15:
     case IMGFMT_RGB15:
-	vo_draw_alpha_rgb15(w,h,src,srca,stride,lvo_mem+2*(y0*bespitch+x0),2*bespitch);
+	vo_draw_alpha_rgb15(w,h,dp,src,srca,stride,lvo_mem+2*(y0*bespitch+x0),2*bespitch);
 	break;
     case IMGFMT_BGR16:
     case IMGFMT_RGB16:
-	vo_draw_alpha_rgb16(w,h,src,srca,stride,lvo_mem+2*(y0*bespitch+x0),2*bespitch);
+	vo_draw_alpha_rgb16(w,h,dp,src,srca,stride,lvo_mem+2*(y0*bespitch+x0),2*bespitch);
 	break;
     case IMGFMT_BGR24:
     case IMGFMT_RGB24:
-	vo_draw_alpha_rgb24(w,h,src,srca,stride,lvo_mem+3*(y0*bespitch+x0),3*bespitch);
+	vo_draw_alpha_rgb24(w,h,dp,src,srca,stride,lvo_mem+3*(y0*bespitch+x0),3*bespitch);
 	break;
     case IMGFMT_BGR32:
     case IMGFMT_RGB32:
-	vo_draw_alpha_rgb32(w,h,src,srca,stride,lvo_mem+4*(y0*bespitch+x0),4*bespitch);
+	vo_draw_alpha_rgb32(w,h,dp,src,srca,stride,lvo_mem+4*(y0*bespitch+x0),4*bespitch);
 	break;
     case IMGFMT_YV12:
     case IMGFMT_IYUV:
     case IMGFMT_I420:
-        vo_draw_alpha_yv12(w,h,src,srca,stride,lvo_mem+bespitch*y0+x0,bespitch);
+        vo_draw_alpha_yv12(w,h,dp,src,srca,stride,lvo_mem+bespitch*y0+x0,bespitch);
         break;
     case IMGFMT_YUY2:
-        vo_draw_alpha_yuy2(w,h,src,srca,stride,lvo_mem+2*(bespitch*y0+x0),bespitch);
+        vo_draw_alpha_yuy2(w,h,dp,src,srca,stride,lvo_mem+2*(bespitch*y0+x0),bespitch);
         break;
     case IMGFMT_UYVY:
-        vo_draw_alpha_yuy2(w,h,src,srca,stride,lvo_mem+2*(bespitch*y0+x0)+1,bespitch);
+        vo_draw_alpha_yuy2(w,h,dp,src,srca,stride,lvo_mem+2*(bespitch*y0+x0)+1,bespitch);
         break;
     default:
-        draw_alpha_null(x0,y0,w,h,src,srca,stride);
+        draw_alpha_null(x0,y0,w,h,dp,src,srca,stride);
     }
 }
 
--- libvo/vo_aa.c	2007-10-07 21:49:28.000000000 +0200
+++ libvo/vo_aa.c	2007-10-08 21:09:26.000000000 +0200
@@ -510,7 +510,7 @@
     aa_close(c);
 }
 
-static void draw_alpha(int x,int y, int w,int h, unsigned char* src, unsigned char *srca, int stride){
+static void draw_alpha(int x,int y, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride){
     int i,j;
     for (i = 0; i < h; i++) {
 	for (j = 0; j < w; j++) {
--- libvo/vo_xv.c	2007-10-07 21:49:28.000000000 +0200
+++ libvo/vo_xv.c	2007-10-08 21:09:26.000000000 +0200
@@ -93,47 +93,83 @@
 static uint32_t drwX, drwY, drwBorderWidth, drwDepth;
 static uint32_t max_width = 0, max_height = 0; // zero means: not set
 
-static void (*draw_alpha_fnc) (int x0, int y0, int w, int h,
+static int support_yuvspu = VO_FALSE;
+static int support_yuyspu = VO_FALSE;
+
+static void (*draw_alpha_fnc) (int x0, int y0, int w, int h, int dp,
                                unsigned char *src, unsigned char *srca,
                                int stride);
 
-static void draw_alpha_yv12(int x0, int y0, int w, int h,
+static void draw_alpha_yv12(int x0, int y0, int w, int h, int dp,
                             unsigned char *src, unsigned char *srca,
                             int stride)
 {
+    switch (dp)  {
+	case DEST_PLANES_U:  {
+    x0 += image_width/2 * (vo_panscan_x >> 1) / (vo_dwidth + vo_panscan_x);
+    vo_draw_alpha_yv12(w, h, dp, src, srca, stride,
+                       xvimage[current_buf]->data +
+                       xvimage[current_buf]->offsets[1] +
+                       xvimage[current_buf]->pitches[1] * y0 + x0,
+                       xvimage[current_buf]->pitches[1]);
+	  break; }
+	case DEST_PLANES_V:  {
+    x0 += image_width/2 * (vo_panscan_x >> 1) / (vo_dwidth + vo_panscan_x);
+    vo_draw_alpha_yv12(w, h, dp, src, srca, stride,
+                       xvimage[current_buf]->data +
+                       xvimage[current_buf]->offsets[2] +
+                       xvimage[current_buf]->pitches[2] * y0 + x0,
+                       xvimage[current_buf]->pitches[2]);
+	  break; }
+	case DEST_PLANES_Y: {
     x0 += image_width * (vo_panscan_x >> 1) / (vo_dwidth + vo_panscan_x);
-    vo_draw_alpha_yv12(w, h, src, srca, stride,
+    vo_draw_alpha_yv12(w, h, dp, src, srca, stride,
                        xvimage[current_buf]->data +
                        xvimage[current_buf]->offsets[0] +
                        xvimage[current_buf]->pitches[0] * y0 + x0,
                        xvimage[current_buf]->pitches[0]);
 }
+	}
 
-static void draw_alpha_yuy2(int x0, int y0, int w, int h,
+}
+
+static void draw_alpha_yuy2(int x0, int y0, int w, int h, int dp,
                             unsigned char *src, unsigned char *srca,
                             int stride)
 {
+  switch (dp) {
+    case DEST_PLANES_Y:
+    x0 += image_width * (vo_panscan_x >> 1) / (vo_dwidth + vo_panscan_x);
+    vo_draw_alpha_yuy2(w, h, dp, src, srca, stride,
+                       xvimage[current_buf]->data +
+                       xvimage[current_buf]->offsets[0] +
+                       xvimage[current_buf]->pitches[0] * y0 + 2 * x0,
+                       xvimage[current_buf]->pitches[0]);
+    break;
+    case DEST_PLANES_YUYV:
     x0 += image_width * (vo_panscan_x >> 1) / (vo_dwidth + vo_panscan_x);
-    vo_draw_alpha_yuy2(w, h, src, srca, stride,
+    vo_draw_alpha_yv12(w, h, dp, src, srca, stride,
                        xvimage[current_buf]->data +
                        xvimage[current_buf]->offsets[0] +
                        xvimage[current_buf]->pitches[0] * y0 + 2 * x0,
                        xvimage[current_buf]->pitches[0]);
+    break;
+    }
 }
 
-static void draw_alpha_uyvy(int x0, int y0, int w, int h,
+static void draw_alpha_uyvy(int x0, int y0, int w, int h, int dp,
                             unsigned char *src, unsigned char *srca,
                             int stride)
 {
     x0 += image_width * (vo_panscan_x >> 1) / (vo_dwidth + vo_panscan_x);
-    vo_draw_alpha_yuy2(w, h, src, srca, stride,
+    vo_draw_alpha_yuy2(w, h, dp, src, srca, stride,
                        xvimage[current_buf]->data +
                        xvimage[current_buf]->offsets[0] +
                        xvimage[current_buf]->pitches[0] * y0 + 2 * x0 + 1,
                        xvimage[current_buf]->pitches[0]);
 }
 
-static void draw_alpha_null(int x0, int y0, int w, int h,
+static void draw_alpha_null(int x0, int y0, int w, int h, int dp,
                             unsigned char *src, unsigned char *srca,
                             int stride)
 {
@@ -328,11 +364,13 @@
     {
         case IMGFMT_YV12:
         case IMGFMT_I420:
+	    support_yuvspu = VO_TRUE;
         case IMGFMT_IYUV:
             draw_alpha_fnc = draw_alpha_yv12;
             break;
         case IMGFMT_YUY2:
         case IMGFMT_YVYU:
+	    support_yuyspu = VO_TRUE;
             draw_alpha_fnc = draw_alpha_yuy2;
             break;
         case IMGFMT_UYVY:
@@ -914,6 +952,14 @@
         case VOCTRL_UPDATE_SCREENINFO:
             update_xinerama_info();
             return VO_TRUE;
+        case VOCTRL_YUVSPU_SUPPORT:
+            return support_yuvspu;
+        case VOCTRL_RGBSPU_SUPPORT:
+	    return VO_FALSE;
+        case VOCTRL_BGRSPU_SUPPORT:
+	    return VO_FALSE;
+        case VOCTRL_YUYSPU_SUPPORT:
+            return support_yuyspu;
     }
     return VO_NOTIMPL;
 }
--- libvo/vo_fbdev2.c	2007-10-07 21:49:28.000000000 +0200
+++ libvo/vo_fbdev2.c	2007-10-08 21:09:26.000000000 +0200
@@ -79,7 +79,7 @@
 static int fb_bpp;		// 32: 32  24: 24  16: 16  15: 15
 static size_t fb_size; // size of frame_buffer
 static int fb_line_len; // length of one line in bytes
-static void (*draw_alpha_p)(int w, int h, unsigned char *src,
+static void (*draw_alpha_p)(int w, int h, int dp, unsigned char *src,
 		unsigned char *srca, int stride, unsigned char *dst,
 		int dstride);
 
@@ -317,7 +317,7 @@
 	return 0;
 }
 
-static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src,
+static void draw_alpha(int x0, int y0, int w, int h, int dp, unsigned char *src,
 		unsigned char *srca, int stride)
 {
 	unsigned char *dst;
@@ -330,7 +330,7 @@
 	dst = next_frame + (in_width * y0 + x0) * fb_pixel_size;
 	dstride = in_width * fb_pixel_size;
 #endif
-	(*draw_alpha_p)(w, h, src, srca, stride, dst, dstride);
+	(*draw_alpha_p)(w, h, dp, src, srca, stride, dst, dstride);
 }
 
 static void draw_osd(void)
@@ -403,6 +403,13 @@
   switch (request) {
   case VOCTRL_QUERY_FORMAT:
     return query_format(*((uint32_t*)data));
+  case VOCTRL_YUVSPU_SUPPORT:
+    return VO_FALSE;
+  case VOCTRL_RGBSPU_SUPPORT:
+    return VO_FALSE;
+  case VOCTRL_BGRSPU_SUPPORT:
+    if (fb_bpp == 32 || fb_bpp==24 || fb_bpp==16 || fb_bpp==15) return VO_TRUE;
+    return VO_FALSE;
   }
   return VO_NOTIMPL;
 }
--- libvo/vo_macosx.m	2007-10-07 21:49:28.000000000 +0200
+++ libvo/vo_macosx.m	2007-10-08 21:09:26.000000000 +0200
@@ -73,17 +73,17 @@
 LIBVO_EXTERN(macosx)
 
 extern void mplayer_put_key(int code);
-extern void vo_draw_text(int dxs,int dys,void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride));
+extern void vo_draw_text(int dxs,int dys,void (*draw_alpha)(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride));
 
-static void draw_alpha(int x0, int y0, int w, int h, unsigned char *src, unsigned char *srca, int stride)
+static void draw_alpha(int x0, int y0, int w, int h, int dp, unsigned char *src, unsigned char *srca, int stride)
 {
 	switch (image_format)
 	{
 		case IMGFMT_RGB32:
-			vo_draw_alpha_rgb32(w,h,src,srca,stride,image_data+4*(y0*image_width+x0),4*image_width);
+			vo_draw_alpha_rgb32(w,h,dp,src,srca,stride,image_data+4*(y0*image_width+x0),4*image_width);
 			break;
 		case IMGFMT_YUY2:
-			vo_draw_alpha_yuy2(w,h,src,srca,stride,image_data + (x0 + y0 * image_width) * 2,image_width*2);
+			vo_draw_alpha_yuy2(w,h,dp,src,srca,stride,image_data + (x0 + y0 * image_width) * 2,image_width*2);
 			break;
 	}
 }
--- libvo/vo_dxr3.c	2007-10-07 21:49:28.000000000 +0200
+++ libvo/vo_dxr3.c	2007-10-08 21:09:26.000000000 +0200
@@ -669,7 +669,7 @@
 	return 0;
 }
 
-static void draw_alpha(int x, int y, int w, int h, unsigned char* src, unsigned char *srca, int srcstride)
+static void draw_alpha(int x, int y, int w, int h, int dp, unsigned char* src, unsigned char *srca, int srcstride)
 {
 #ifdef SPU_SUPPORT
 	unsigned char *buf = &osdpicbuf[(y * osdpicbuf_w) + x];
--- command.c	2007-10-07 21:49:33.000000000 +0200
+++ command.c	2007-10-23 16:40:57.000000000 +0200
@@ -2772,16 +2772,29 @@
 		if (mpctx->stream->type != STREAMTYPE_DVDNAV)
 		    break;
 
-		if (mp_dvdnav_handle_input
-		    (mpctx->stream, cmd->args[0].v.i, &button)) {
-		    uninit_player(INITED_ALL - (INITED_STREAM | INITED_INPUT |
-				   (fixed_vo ? INITED_VO : 0)));
-		    brk_cmd = 2;
-		} else if (button > 0)
+		mp_dvdnav_handle_input(mpctx->stream,
+		    cmd->args[0].v.i, &button);
+		if (button > 0)
 		    set_osd_msg(OSD_MSG_TEXT, 1, osd_duration,
 				"Selected button number %d", button);
 	    }
 	    break;
+	case MP_CMD_SWITCH_TITLE:{
+		if (mpctx->stream->type != STREAMTYPE_DVDNAV)
+		    break;
+
+		mp_dvdnav_switch_title(mpctx->stream,
+		    cmd->args[0].v.i);
+	    }
+	    break;
+	case MP_CMD_SWITCH_CHAPTER:{
+		if (mpctx->stream->type != STREAMTYPE_DVDNAV)
+		    break;
+
+		mp_dvdnav_switch_chapter(mpctx->stream,
+		    cmd->args[0].v.i);
+	    }
+	    break;
 #endif
 
 	default:
--- libmenu/menu.c	2007-10-07 21:49:32.000000000 +0200
+++ libmenu/menu.c	2007-10-08 21:09:27.000000000 +0200
@@ -21,6 +21,7 @@
 #include "m_option.h"
 #include "m_struct.h"
 #include "menu.h"
+#include "libvo/video_out.h"
 
 extern menu_info_t menu_info_cmdlist;
 extern menu_info_t menu_info_pt;
@@ -256,7 +257,7 @@
 
 ///////////////////////////// Helpers ////////////////////////////////////
 
-typedef void (*draw_alpha_f)(int w,int h, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride);
+typedef void (*draw_alpha_f)(int w,int h, int dp, unsigned char* src, unsigned char *srca, int srcstride, unsigned char* dstbase,int dststride);
 
 inline static draw_alpha_f get_draw_alpha(uint32_t fmt) {
   switch(fmt) {
@@ -369,7 +370,7 @@
   while (*txt) {
     int c=utf8_get_char(&txt);
     if ((font=vo_font->font[c])>=0 && (x + vo_font->width[c] <= mpi->w) && (y + vo_font->pic_a[font]->h <= mpi->h))
-      draw_alpha(vo_font->width[c], vo_font->pic_a[font]->h,
+      draw_alpha(vo_font->width[c], vo_font->pic_a[font]->h,DEST_PLANES_Y,
 		 vo_font->pic_b[font]->bmp+vo_font->start[c],
 		 vo_font->pic_a[font]->bmp+vo_font->start[c],
 		 vo_font->pic_a[font]->w,
@@ -539,7 +540,7 @@
       if(font >= 0) {
  	int cs = (vo_font->pic_a[font]->h - vo_font->height) / 2;
 	if ((sx + vo_font->width[c] < xmax)  &&  (sy + vo_font->height < ymax) )
-	  draw_alpha(vo_font->width[c], vo_font->height,
+	  draw_alpha(vo_font->width[c], vo_font->height, DEST_PLANES_Y,
 		     vo_font->pic_b[font]->bmp+vo_font->start[c] +
 		     cs * vo_font->pic_a[font]->w,
 		     vo_font->pic_a[font]->bmp+vo_font->start[c] +
@@ -647,7 +648,7 @@
     char pic[stride*h],pic_alpha[stride*h];
     memset(pic,g,stride*h);
     memset(pic_alpha,alpha,stride*h);
-    draw_alpha(w,h,pic,pic_alpha,stride,
+    draw_alpha(w,h,DEST_PLANES_Y,pic,pic_alpha,stride,
                mpi->planes[0] + y * mpi->stride[0] + x * (mpi->bpp>>3),
                mpi->stride[0]);
   }
--- mplayer.c	2007-10-07 21:49:33.000000000 +0200
+++ mplayer.c	2007-10-23 16:20:21.000000000 +0200
@@ -170,7 +170,20 @@
 #endif
 
 #ifdef USE_DVDNAV
+#include "libmpcodecs/img_format.h"
+#include "libmpcodecs/mp_image.h"
+#include "libvo/fastmemcpy.h"
 #include "stream/stream_dvdnav.h"
+// vo color mode:
+// -1 : no settings
+//  0 : Y
+//  1 : YUV
+//  2 : RGB
+//  3 : BGR
+//  4 : YUYV
+int dvdnav_color_spu_flg = -1;
+// enable/disable SPU menu button
+int dvdnav_color_spu = 1;
 #endif
 
 #include "libmpcodecs/dec_audio.h"
@@ -614,6 +627,17 @@
     current_module="uninit_vo";
     mpctx->video_out->uninit();
     mpctx->video_out=NULL;
+#ifdef USE_DVDNAV
+    // free stored decoded image
+    if (mpctx->smpi) free_mp_image(mpctx->smpi);
+    mpctx->smpi=NULL;
+    // free last video read frame
+    if (mpctx->last_buffer) free(mpctx->last_buffer);
+    // clear buffers
+    mpctx->last_buffer=NULL;
+    mpctx->last_start=NULL;
+    mpctx->last_in_size=0;
+#endif
   }
 
   // Must be after libvo uninit, as few vo drivers (svgalib) have tty code.
@@ -1679,6 +1703,287 @@
     return time_frame;
 }
 
+// DVDNAV *FIXME*
+#ifdef USE_DVDNAV
+//
+// store decoded video image
+//
+mp_image_t* mp_dvdnav_copympi(mp_image_t* tompi,
+        mp_image_t* frommpi) {
+    mp_image_t* mpi;
+
+    if (!frommpi) return NULL;
+    // Do not store B-frames
+    if (frommpi->pict_type==3) return tompi;
+    if (tompi && tompi->w==frommpi->w &&
+	    tompi->h==frommpi->h &&
+	    tompi->imgfmt==frommpi->imgfmt)
+        mpi=tompi;
+    else {
+        if (tompi) free_mp_image(tompi);
+        if (frommpi->w==0 || frommpi->h==0) return NULL;
+        mpi=alloc_mpi(frommpi->w,frommpi->h,frommpi->imgfmt);
+    }
+    copy_mpi(mpi,frommpi);
+    return mpi;
+}
+
+//
+// set audio in dvdnav
+//
+static int mp_dvdnav_audio_handle() {
+
+    int dvdnav_audio_num=mp_dvdnav_get_audio(mpctx->stream);
+    int current_id=mpctx->demuxer->audio->id;
+    int dvdnav_audio;
+    
+    dvdnav_audio=dvdnav_aid_from_audio_num(mpctx->stream,dvdnav_audio_num);
+    if(dvdnav_audio==-1) return 0;					// fail seek
+    if(current_id==dvdnav_audio) return 0;				// no change
+    audio_id = demuxer_switch_audio(mpctx->demuxer, dvdnav_audio);	// switch audio
+    if((current_id & 0x0F)==(dvdnav_audio &0x0F)) return 0;		// if unchanged audio codec then no reinit audio
+
+    if(audio_id == -2 || (audio_id > -1 && mpctx->demuxer->audio->id != current_id && current_id != -2))
+        uninit_player(INITED_AO | INITED_ACODEC);
+    if(audio_id > -1 && mpctx->demuxer->audio->id != current_id) {
+        sh_audio_t *sh2;
+        sh2 = mpctx->demuxer->a_streams[mpctx->demuxer->audio->id];
+        if(sh2) {
+	        sh2->ds = mpctx->demuxer->audio;
+	        mpctx->sh_audio = sh2;
+	        reinit_audio_chain();
+	        }
+        }
+    return 1;
+}
+
+//
+// set dvdnav subtile
+//
+static void mp_dvdnav_spu_handle() {
+    if(!mp_dvdnav_is_spu_change(mpctx->stream)) return;		// is unchanged dvdnav subtitle
+    int dvdnav_spu=mp_dvdnav_get_spu(mpctx->stream);
+    if (!mpctx->d_sub) return;
+    if(dvdnav_spu<0) dvdnav_spu=-2;
+    if (mpctx->d_sub) {
+        dvdsub_id = dvdnav_spu;
+        mpctx->d_sub->id = dvdnav_spu;
+    }
+return;
+}
+
+//
+// set dvd menu buttons
+//
+static void mp_dvdnav_highlight_handle(int stream_is_change) {
+    nav_highlight_t highlight;
+    unsigned int *spu_clut;
+
+    if (!dvdnav_color_spu) return;					// is disable dvdnav color spu
+    if (dvdnav_color_spu_flg==-1) {					// is unsettings vo color mode
+        dvdnav_color_spu_flg=0;
+        if (mpctx->video_out) {					// query vo color mode
+            if (!dvdnav_color_spu_flg && mpctx->video_out->control(VOCTRL_YUVSPU_SUPPORT,NULL)==VO_TRUE)
+	            dvdnav_color_spu_flg=DVDNAV_SPU_YUV;
+	        if (!dvdnav_color_spu_flg && mpctx->video_out->control(VOCTRL_YUYSPU_SUPPORT,NULL)==VO_TRUE)
+	            dvdnav_color_spu_flg=DVDNAV_SPU_YUY;
+	        if (!dvdnav_color_spu_flg && mpctx->video_out->control(VOCTRL_RGBSPU_SUPPORT,NULL)==VO_TRUE)
+	            dvdnav_color_spu_flg=DVDNAV_SPU_RGB;
+	        if (!dvdnav_color_spu_flg && mpctx->video_out->control(VOCTRL_BGRSPU_SUPPORT,NULL)==VO_TRUE)
+	            dvdnav_color_spu_flg=DVDNAV_SPU_BGR;
+//	        if (!dvdnav_color_spu_flg)
+//	            mp_msg(MSGT_CPLAYER,MSGL_INFO,MSGTR_MPDVDNAV_NoColorSpu);
+	        }
+        }
+    spu_clut = mp_dvdnav_get_spu_clut(mpctx->stream);
+    mp_dvdnav_get_highlight(mpctx->stream,&highlight);
+    if (highlight.sx==0 && highlight.sy==0 && highlight.ex==0 && highlight.ey==0) {	// is no button
+        if (stream_is_change) {
+	        spudec_update_palette(vo_spudec,spu_clut);
+	        spudec_dvdnav_mode(vo_spudec, 0, dvdnav_color_spu_flg);	/* spu menu button off */
+	        spudec_dvdnav_area(vo_spudec,highlight.sx,highlight.sy,highlight.ex,
+	        highlight.ey,highlight.palette); /* set spu button area & palette */
+	        if(vo_spudec) spudec_reset(vo_spudec);
+	        vo_osd_changed(OSDTYPE_SPU);
+	        }
+        } else {
+        spudec_update_palette(vo_spudec,spu_clut);
+        spudec_dvdnav_mode(vo_spudec, 1, dvdnav_color_spu_flg);	/* spu menu button on */
+        spudec_dvdnav_area(vo_spudec,highlight.sx,highlight.sy,highlight.ex,
+	    highlight.ey,highlight.palette); /* set spu button area & palette */
+        vo_osd_changed(OSDTYPE_SPU);
+        if (!vo_spudec || !spudec_visible(vo_spudec)) {		// if unsucessful spu button visible
+	        osd_set_nav_box(highlight.sx,highlight.sy,highlight.ex,highlight.ey);	// then use simple box
+	        vo_osd_changed(OSDTYPE_DVDNAV);
+	        } else {
+	        osd_set_nav_box(0,0,0,0);				// id sucessful spu button visible the 
+	        vo_osd_changed(OSDTYPE_DVDNAV);				// then hide simple box
+	        }
+        }
+}
+
+//
+// query: dvdnav stream change (cell, title, audio or subtitle)
+//
+static int mp_dvdnav_is_stream_change() {
+    if (!mp_dvdnav_is_change(mpctx->stream)) return 0;
+    //mp_dvdnav_set_audio_channels(mpctx->stream,mpctx->demuxer);
+    return 1;
+}
+
+//
+// video frame preprocess: before decode_video()
+//
+static void* mp_dvdnav_decode_video_pre(int *in_size,
+    unsigned char **start, mp_image_t* decoded_frame) {
+    int dvdnav_audio,dvdnav_spu;
+
+    // change in dvdnav stream
+    if (mp_dvdnav_iscellchage(mpctx->stream,0)) {
+        // suspend read from dvdnav stream, and set auto_wait
+        mp_dvdnav_wait_read(mpctx->stream, 1, 1);
+        // free last stored frame image
+        if (mpctx->smpi) free_mp_image(mpctx->smpi);
+        mpctx->smpi=NULL;
+        // clear buffers
+        if (mpctx->last_buffer) free(mpctx->last_buffer);
+        mpctx->last_buffer=NULL;
+        mpctx->last_in_size=0;
+        if (mpctx->d_sub) {
+            dvdsub_id = -2;
+            if(0<=(dvdnav_spu=mp_dvdnav_get_spu(mpctx->stream))) {
+                dvdsub_id = dvdnav_spu;
+                mpctx->d_sub->id = dvdnav_spu;
+            }
+        }
+        if (mpctx->sh_video) {
+            // clear video pts
+            mpctx->d_video->pts=0.0f;
+            mpctx->sh_video->pts=0.0f;
+            mpctx->sh_video->i_pts=0.0f;
+            mpctx->sh_video->last_pts=0.0f;
+            mpctx->sh_video->num_buffered_pts=0;
+            mpctx->sh_video->num_frames=0;
+            mpctx->sh_video->num_frames_decoded=0;
+            mpctx->sh_video->timer=0.0f;
+            mpctx->sh_video->stream_delay=0.0f;
+            mpctx->demuxer->stream_pts=MP_NOPTS_VALUE;
+            mpctx->sh_video->timer=0;
+        }
+        if (mpctx->sh_audio) {
+            dvdnav_audio=dvdnav_aid_from_audio_num(mpctx->stream,
+                mp_dvdnav_get_audio(mpctx->stream));
+            if(dvdnav_audio!=-1 && mpctx->demuxer->audio->id!=dvdnav_audio)
+                audio_id = demuxer_switch_audio(mpctx->demuxer, dvdnav_audio);	// switch audio
+            // free audio packs and reset
+            ds_free_packs(mpctx->d_audio);
+            audio_delay -= mpctx->sh_audio->stream_delay;
+            mpctx->delay=-audio_delay;
+            mpctx->audio_out->reset();
+            resync_audio_stream(mpctx->sh_audio);
+        }
+        audio_delay=0.0f;
+        correct_pts=0;
+        // clear all eof flags
+        mpctx->d_video->eof=mpctx->d_audio->eof=
+	    mpctx->stream->eof=0;
+        // set nav menu
+        mp_dvdnav_highlight_handle(1);
+        // enable read from dvdnav stream
+        mp_dvdnav_wait_read(mpctx->stream, 0, 1);
+        // reset cell change flag
+        mp_dvdnav_iscellchage(mpctx->stream,1);
+    }
+// Wait or still frame (in_size==-1): if frame decode OK then return stored image
+    if (*in_size<0 && !mpctx->last_buffer && mpctx->smpi &&
+	        !mpctx->libmpeg2_count)
+        decoded_frame=mpctx->smpi;
+    mpctx->dup_frame=0;
+    if (*in_size<0 && mpctx->last_buffer) {
+        mpctx->dup_frame=1;
+        if (!mpctx->libmpeg2_count)
+	    mpctx->libmpeg2_count=5;
+        // is valid last video buffer (required libmpeg2!)
+        if (mpctx->last_start) {
+             // Set start, in_size and copy frame data from stored frame
+            *start=mpctx->last_start;
+            *in_size=mpctx->last_in_size;
+            memcpy(*start,mpctx->last_buffer,*in_size);
+        } else {
+            *start=mpctx->last_buffer;
+            *in_size=mpctx->last_in_size;
+        }
+    }
+    return decoded_frame;
+}
+
+//
+// video frame postprocess: after decode_video()
+//
+static void* mp_dvdnav_decode_video_post(int in_size,
+	unsigned char *start, mp_image_t* decoded_frame,
+	sh_video_t *sh_video, int drop_frame) {
+    float len;
+
+    if (in_size<0) {
+        if (mpctx->last_buffer) {
+            // free buffer
+            free(mpctx->last_buffer);
+            mpctx->last_buffer=NULL;
+            mpctx->last_in_size=0;
+        }
+        // get duration of part
+        len = demuxer_get_time_length(mpctx->demuxer);
+        if ((mpctx->sh_video->pts>=len || !mpctx->smpi) &&
+		        mpctx->sh_video->pts>0.0 && len>0.0) {
+            // clear still frame in dvdnav
+            mp_dvdnav_still_skip(mpctx->stream);
+            // clear wait in dvdnav
+            mp_dvdnav_wait_skip(mpctx->stream);
+        }
+        // increment video frame
+        mpctx->sh_video->pts+=1/mpctx->sh_video->fps;
+    } else {
+        if (mpctx->dup_frame) {
+            if (mpctx->libmpeg2_count)
+		        mpctx->libmpeg2_count--;
+            if (!mpctx->libmpeg2_count) {
+                // clear buffers
+                if (mpctx->last_buffer)
+		    free(mpctx->last_buffer);
+                mpctx->last_buffer=NULL;
+                mpctx->last_in_size=0;
+                if (!decoded_frame && !mpctx->smpi) {
+                    mp_msg(MSGT_CPLAYER,MSGL_ERR,
+                        "Can't decode still frame.\n"
+                        "Please, you try play dvdnav to -vc ffmpeg12 option.\n");
+                    mpctx->eof=1;
+                }
+            }
+        // no duplicate mode
+        } else {
+            // clear buffer
+            if (mpctx->last_buffer)
+		        free(mpctx->last_buffer);
+            mpctx->last_in_size=in_size;
+            // allocate buffer and store read video frame data
+            mpctx->last_buffer=malloc(in_size);
+            mpctx->last_start=start;
+            if (mpctx->last_buffer)
+                memcpy(mpctx->last_buffer,start,in_size);
+            else
+                mpctx->last_in_size=-1;
+        }
+        // if decoded OK and no stored image then store image
+        if (decoded_frame && mpctx->smpi!=decoded_frame) {
+	        mpctx->smpi=mp_dvdnav_copympi(mpctx->smpi,decoded_frame);
+        }
+    }
+    return decoded_frame;
+}
+
+#endif
+
 static void adjust_sync_and_print_status(int between_frames, float timing_error)
 {
     current_module="av_sync";
@@ -1881,8 +2186,16 @@
     //============================== SLEEP: ===================================
 
     // flag 256 means: libvo driver does its timing (dvb card)
-    if (*time_frame > 0.001 && !(vo_flags&256))
+    update_osd_msg();
+    if (*time_frame > 0.001 && !(vo_flags&256)) {
 	*time_frame = timing_sleep(*time_frame);
+	// if we slept long call this once BEFORE adding new messages,
+	// otherwise it can kill changed messages as "too old" on the next call
+	update_osd_msg();
+	if (*time_frame > 0)
+	    return 1;
+    }
+
     return frame_time_remaining;
 }
 
@@ -2002,7 +2315,7 @@
     *blit_frame = 0; // Don't blit if we hit EOF
     if (!correct_pts) {
 	unsigned char* start=NULL;
-	void *decoded_frame;
+	void *decoded_frame=NULL;
 	int drop_frame=0;
 	int in_size;
 
@@ -2010,6 +2323,17 @@
 	frame_time = sh_video->next_frame_time;
 	in_size = video_read_frame(sh_video, &sh_video->next_frame_time,
 				   &start, force_fps);
+#ifdef USE_DVDNAV
+    // wait, still frame or EOF
+    if (mpctx->stream->type==STREAMTYPE_DVDNAV && in_size < 0) {
+        if (mp_dvdnav_isreallyeof(mpctx->stream)) printf("really eof *************\n");
+        if (mp_dvdnav_isreallyeof(mpctx->stream)) return -1;
+        // if not (wait, still frame) then clear eof flags
+        if (mpctx->d_video) mpctx->d_video->eof=0;
+        if (mpctx->d_audio) mpctx->d_audio->eof=0;
+        mpctx->stream->eof=0;
+    } else
+#endif
 	if (in_size < 0)
 	    return -1;
 	if (in_size > max_framesize)
@@ -2040,8 +2364,22 @@
 	update_teletext(sh_video, mpctx->demuxer, 0);
 	update_osd_msg();
 	current_module = "decode_video";
+#ifdef USE_DVDNAV
+    if (mpctx->stream->type==STREAMTYPE_DVDNAV)
+        // call dvdnav video preprocess
+        decoded_frame=mp_dvdnav_decode_video_pre(&in_size,
+	    &start,decoded_frame);
+    // if stored image then do not call decode_video()
+    if (in_size>0 && !decoded_frame)
+#endif
 	decoded_frame = decode_video(sh_video, start, in_size, drop_frame,
 				     sh_video->pts);
+#ifdef USE_DVDNAV
+    if (mpctx->stream->type==STREAMTYPE_DVDNAV)
+        // call dvdnav video postprocess
+        decoded_frame=mp_dvdnav_decode_video_post(in_size,
+	    start,decoded_frame,sh_video, drop_frame);
+#endif
 	current_module = "filter_video";
 	*blit_frame = (decoded_frame && filter_video(sh_video, decoded_frame,
 						    sh_video->pts));
@@ -2326,7 +2664,7 @@
     if(strstr(base, "gmplayer"))
           use_gui=1;
   }
-
+  if (use_gui) enable_mouse_movements=1;
     mconfig = m_config_new();
     m_config_register_options(mconfig,mplayer_opts);
     // TODO : add something to let modules register their options
@@ -3351,6 +3689,17 @@
     end_at.type = END_AT_NONE;
 }
 
+#ifdef USE_DVDNAV
+// free stored image
+if (mpctx->smpi) free_mp_image(mpctx->smpi);
+mpctx->smpi=NULL;
+if (mpctx->stream->type==STREAMTYPE_DVDNAV) {
+    // enable read from dvdnav stream and set auto wait mode
+    mp_dvdnav_wait_read(mpctx->stream, 0, 1);
+    // clear cell change flag
+    mp_dvdnav_iscellchage(mpctx->stream,1);
+    }
+#endif
 
 while(!mpctx->eof){
     float aq_sleep_time=0;
@@ -3432,6 +3781,8 @@
         if (!frame_time_remaining && blit_frame) {
 	   unsigned int t2=GetTimer();
 
+	   update_osd_msg();
+	   mpctx->video_out->draw_osd();
 	   if(vo_config_count) mpctx->video_out->flip_page();
 	   mpctx->num_buffered_frames--;
 
@@ -3476,10 +3827,22 @@
 
 #ifdef USE_DVDNAV
  if (mpctx->stream->type == STREAMTYPE_DVDNAV) {
+    if(dvdnav_color_spu==0) {
    nav_highlight_t hl;
    mp_dvdnav_get_highlight (mpctx->stream, &hl);
    osd_set_nav_box (hl.sx, hl.sy, hl.ex, hl.ey);
    vo_osd_changed (OSDTYPE_DVDNAV);
+ } else {
+    if (mp_dvdnav_is_stream_change()) {	// is cell change (title, part, audio, subtitle)
+	    mp_dvdnav_audio_handle();	// call audio process
+	    mp_dvdnav_spu_handle();		// call subtitle process
+#ifdef HAVE_NEW_GUI
+	    if ( use_gui ) guiGetEvent( guiSetStream,(char *)mpctx->stream );	// update gui dvdnav stream info
+#endif
+	    mp_dvdnav_highlight_handle(1);	// update dvdnav menu
+	    } else
+	    mp_dvdnav_highlight_handle(0);
+    }
  }
 #endif
  
@@ -3488,6 +3851,7 @@
   current_module="pause";
 
   if (mpctx->osd_function == OSD_PAUSE) {
+      update_osd_msg();
       pause_loop();
       mpctx->was_paused = 1;
   }
@@ -3530,6 +3894,7 @@
 
 if(rel_seek_secs || abs_seek_pos){
   if (seek(mpctx, rel_seek_secs, abs_seek_pos) >= 0) {
+      time_frame = 0;
         // Set OSD:
       if(!loop_seek){
 	if( !edl_decision )
--- dvdread/ifo_read.c	2007-10-07 21:49:28.000000000 +0200
+++ dvdread/ifo_read.c	2007-10-14 12:59:03.000000000 +0200
@@ -755,6 +755,10 @@
   B2N_16(pgc->cell_playback_offset);
   B2N_16(pgc->cell_position_offset);
 
+  for(i = 0; i < 8; i++)
+    B2N_16(*((uint16_t*)&pgc->audio_control[i]));
+  for(i = 0; i < 32; i++)
+    B2N_32(*((uint32_t*)&pgc->subp_control[i]));
   for(i = 0; i < 16; i++)
     B2N_32(pgc->palette[i]);
   
--- dvdread/ifo_types.h	2007-10-07 21:49:28.000000000 +0200
+++ dvdread/ifo_types.h	2007-10-14 12:59:59.000000000 +0200
@@ -424,18 +424,18 @@
   unsigned int zero4     : 3;
   unsigned int s_panscan : 5; /* stream for 16:9 with pan&scan data on 4:3 display */
 #else
-  unsigned int s_4p3     : 5; /* stream for 4:3 on any display */
-  unsigned int zero1     : 2;
-  unsigned int present   : 1;
-
-  unsigned int s_wide    : 5; /* stream for 16:9 on widescreen display */
-  unsigned int zero2     : 3;
+  unsigned int s_panscan : 5; /* stream for 16:9 with pan&scan data on 4:3 display */
+  unsigned int zero4     : 3;
 
   unsigned int s_lbox    : 5; /* stream for 16:9 on letterboxed 4:3 display */
   unsigned int zero3     : 3;
 
-  unsigned int s_panscan : 5; /* stream for 16:9 with pan&scan data on 4:3 display */
-  unsigned int zero4     : 3;
+  unsigned int s_wide    : 5; /* stream for 16:9 on widescreen display */
+  unsigned int zero2     : 3;
+
+  unsigned int s_4p3     : 5; /* stream for 4:3 on any display */
+  unsigned int zero1     : 2;
+  unsigned int present   : 1;
 #endif
 } ATTRIBUTE_PACKED subp_mapping_t;
 
@@ -447,12 +447,13 @@
   unsigned int present : 1;
   unsigned int zero1   : 4;
   unsigned int s_audio : 3;
+  uint8_t zero2;
 #else
+  uint8_t zero2;
   unsigned int s_audio : 3;
   unsigned int zero1   : 4;
   unsigned int present : 1;
 #endif
-  uint8_t zero2;
 } ATTRIBUTE_PACKED audio_mapping_t;
 
 /**
--- spudec.c	2007-10-07 21:49:33.000000000 +0200
+++ spudec.c	2007-10-23 17:35:17.000000000 +0200
@@ -94,6 +94,52 @@
   int spu_changed;
   unsigned int forced_subs_only;     /* flag: 0=display all subtitle, !0 display only forced subtitles */
   unsigned int is_forced_sub;         /* true if current subtitle is a forced subtitle */
+
+  packet_t *last_packet;
+  unsigned int widthuv, heightuv, strideuv;
+  unsigned int start_coluv, end_coluv;
+  unsigned int start_rowuv, end_rowuv;
+  size_t image_sizeuv;
+  size_t scaled_image_sizeuv;
+  size_t image_sizeyuy;
+
+  unsigned int scaled_frame_widthuv, scaled_frame_heightuv;
+  unsigned int scaled_start_coluv, scaled_start_rowuv;
+  unsigned int scaled_widthuv, scaled_heightuv, scaled_strideuv;
+  unsigned char *scaled_imageu;
+  unsigned char *scaled_imagev;
+  unsigned char *scaled_aimageuv;
+
+  unsigned int hpalette[4];
+  unsigned int halpha[4];
+  unsigned int hcuspal[4];
+
+  unsigned char *imageu;		/* u value from yUv */
+  unsigned char *imagev;		/* v value from yuV*/
+  unsigned char *aimageuv;		/* alpha with uv*/
+  unsigned char *imageyuy;		/* yuy2 */
+  unsigned char *aimageyuy;		/* alpha with yuy2*/
+  unsigned int strideyuy;
+
+  int dvdnav_color_spu;		/* flag: 0 = grayscale SPU, 1 = YUV color SPU 2 = RGB 3 = BGR */
+
+  int dvdnav_menu;		/* flag: 0=normal subtitle, 1=dvdnav menu */
+  unsigned int dvdnav_sx;	/* dvdnav menu item box */
+  unsigned int dvdnav_ex;
+  unsigned int dvdnav_sy;
+  unsigned int dvdnav_ey;
+  unsigned int dvdnav_modify;	/* dvdnav menu item box is modify */
+  uint32_t     dvdnav_palette;	/* dvdnav menu button palette */
+  unsigned int dvdnav_x0;	/* dvdnav menu item draw_alpha coordinates */
+  unsigned int dvdnav_y0;
+  unsigned int dvdnav_w;
+  unsigned int dvdnav_h;
+  unsigned char *dvdnav_image;	/* dvdnav menu item image */
+  unsigned char *dvdnav_aimage;	/* dvdnav menu item alpha */
+  unsigned int dvdnav_stride;
+  unsigned int dvdnav_allocated;
+  unsigned int dvdnav_scalex;
+  unsigned int dvdnav_scaley;
 } spudec_handle_t;
 
 static void spudec_queue_packet(spudec_handle_t *this, packet_t *packet)
@@ -213,11 +259,147 @@
   } else {
     mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: update_spu: malloc requested %d bytes\n", 2 * this->stride * this->height);
   }
+//
+// Cut the sub to visible part UV planes
+//
+  unsigned char *imageu;
+  unsigned char *imagev;
+  switch (this->dvdnav_color_spu) {
+    case DVDNAV_SPU_YUV:
+    case DVDNAV_SPU_YUY:
+      for (fy = 0; fy < this->image_sizeuv && !this->aimageuv[fy]; fy++);
+      for (ly = this->strideuv * this->heightuv-1;
+        ly && !this->aimageuv[ly]; ly--);
+      first_y = fy / this->strideuv;
+      last_y = ly / this->strideuv;
+      this->start_rowuv += first_y;
+      // Some subtitles trigger this condition
+      if (last_y + 1 > first_y ) {
+	  this->heightuv = last_y - first_y +1;
+        } else {
+	  this->heightuv = 0;
+	  this->image_sizeuv = 0;
+	  return;
+        }
+      //  printf("new h %d new start %d (sz %d st %d)---\n\n", this->height, this->start_row, this->image_size, this->stride);
+      imageu = malloc(3 * this->strideuv * this->heightuv);
+      if(imageu){
+        this->image_sizeuv = this->strideuv * this->heightuv;
+        imagev = imageu + this->image_sizeuv;
+        aimage = imagev + this->image_sizeuv;
+        memcpy(imageu, this->imageu + this->strideuv * first_y,
+	    this->image_sizeuv);
+        memcpy(imagev, this->imagev + this->strideuv * first_y,
+	    this->image_sizeuv);
+        memcpy(aimage, this->aimageuv + this->strideuv * first_y,
+	    this->image_sizeuv);
+        free(this->imageu);
+        this->imageu = imageu;
+        this->imagev = imagev;
+        this->aimageuv = aimage;
+        } else {
+          mp_msg(MSGT_SPUDEC, MSGL_FATAL,
+	    "Fatal: update_spu: malloc requested %d bytes\n",
+	    3 * this->strideuv * this->height);
+        }
+      break;
+    case DVDNAV_SPU_RGB:
+    case DVDNAV_SPU_BGR:
+      this->image_sizeuv = this->stride * this->height;
+      imageu = malloc(2 * this->stride * this->height);
+      if(imageu){
+        imagev = imageu + this->image_size;
+        memcpy(imageu, this->imageu + this->stride * first_y, this->image_size);
+        memcpy(imagev, this->imagev + this->stride * first_y, this->image_size);
+        free(this->imageu);
+        this->imageu = imageu;
+        this->imagev = imagev;
+        this->aimageuv = NULL;
+      } else {
+        mp_msg(MSGT_SPUDEC, MSGL_FATAL,
+	    "Fatal: update_spu: malloc requested %d bytes\n",
+	    2 * this->stride * this->height);
+      }
+      break;
+    }
+}
+
+//
+// Convert yuv color to rgb color
+//
+void spu_yuv_to_rgb(unsigned int y,unsigned int u,unsigned int v,
+    unsigned int *r,unsigned int *g,unsigned int *b)
+{
+int ty,tu,tv;
+int tr,tg,tb;
+ty=y;tv=u;tu=v;
+tr = (298*(ty-16)+408*(tv-128))/256;
+tg = (298*(ty-16)-100*(tu-128)-208*(tv-128))/256;
+tb = (298*(ty-16)+516*(tu-128))/256;
+if(tr>255) tr=255; if(tr<0) tr=0;
+if(tg>255) tg=255; if(tg<0) tg=0;
+if(tb>255) tb=255; if(tb<0) tb=0;
+*r=tr; *g=tg; *b=tb;
+return;
+}
+
+//
+// Fill to spu image buffer
+//	y : image col
+//	x : start pos in image row
+//	len : fill length in image row
+//	color : Y: (YUV,YUY,Y), Red: (RGB) or Blue: (BGR)
+//	coloru: U: (YUV,YUY), Green: (RGB,BGR)
+//	colorv: V: (YUV,YUY), Blue: (RGB) or Red (BGR)
+//	alpha: alpha channel
+static void spudec_process_fill(spudec_handle_t *this, int x, int y, int len,
+    unsigned char color, unsigned char coloru, unsigned char colorv,
+    unsigned char alpha)
+{
+unsigned int corrx, corry, corrl;
+if (this->stride-x-len<0) return;
+if (len<0) return;
+switch (this->dvdnav_color_spu)
+  {
+  case DVDNAV_SPU_YUV:
+  case DVDNAV_SPU_YUY:
+    corry=y & 0x01;
+    corrx=x & 0x01;
+    corrl=len & 0x01;
+    memset(this->image + y * this->stride + x, color, len);
+    memset(this->aimage + y * this->stride + x, alpha, len);
+    memset(this->imageu + (y-corry)/2 * this->strideuv + (x+corrx)/2, coloru,
+	(len-corrl)/2);
+    memset(this->imagev + (y-corry)/2 * this->strideuv + (x+corrx)/2, colorv,
+	(len-corrl)/2);
+    memset(this->aimageuv + (y-corry)/2 * this->strideuv + (x+corrx)/2, alpha,
+	(len-corrl)/2);
+    break;
+  case DVDNAV_SPU_RGB:
+  case DVDNAV_SPU_BGR:
+    memset(this->image + y * this->stride + x, color, len);
+    memset(this->imageu + y * this->stride + x, coloru, len);
+    memset(this->imagev + y * this->stride + x, colorv, len);
+    memset(this->aimage + y * this->stride + x, alpha, len);
+    break;
+  default:
+    memset(this->image + y * this->stride + x, color, len);
+    memset(this->aimage + y * this->stride + x, alpha, len);
+    break;
+}
 }
 
 static void spudec_process_data(spudec_handle_t *this, packet_t *packet)
 {
   unsigned int cmap[4], alpha[4];
+  unsigned int thpalette[4], thalpha[4];	/* dvdnav highlight menu palette */
+  unsigned int hcmap[4], halpha[4];		/* dvdnav highlight map */
+  unsigned int cmapu[4], cmapv[4];
+  unsigned int hcmapu[4], hcmapv[4];
+  unsigned int control_start;
+  unsigned int current_nibble[2];
+  unsigned int ty,tu,tv,tr,tg,tb;
+  int deinterlace_oddness;
   unsigned int i, x, y;
 
   this->scaled_frame_width = 0;
@@ -229,6 +411,18 @@
   this->height = packet->height;
   this->width = packet->width;
   this->stride = packet->stride;
+  this->strideuv = packet->stride;
+  control_start = packet->control_start;
+  current_nibble[0]=packet->current_nibble[0];
+  current_nibble[1]=packet->current_nibble[1];
+  deinterlace_oddness=packet->deinterlace_oddness;
+
+  this->start_coluv = packet->start_col/2;
+  this->end_coluv = packet->end_col/2;
+  this->start_rowuv = packet->start_row/2;
+  this->end_rowuv = packet->end_row/2;
+  this->heightuv = packet->height/2+1;
+  this->widthuv = packet->width/2+1;
   for (i = 0; i < 4; ++i) {
     alpha[i] = mkalpha(packet->alpha[i]);
     if (alpha[i] == 0)
@@ -244,7 +438,92 @@
 	cmap[i] = 256 - alpha[i];
     }
   }
-
+  if (this->dvdnav_menu) {
+    for (i = 0; i < 4; ++i) {	/* use button palette */
+      thalpha[i]=(this->dvdnav_palette >> ((3-i)*4)) & 0x0f;
+      thpalette[i]=(this->dvdnav_palette >> (16+(3-i)*4)) & 0x0f;
+      halpha[i] = mkalpha(thalpha[i]);
+      hcmap[i] = ((this->global_palette[thpalette[i]] >> 16) & 0xff);
+      if (alpha[i] == 0) {cmap[i] = 0; cmapu[i] = 0; cmapv[i] = 0;} else {
+        if (cmap[i] + alpha[i] > 255)
+	  cmap[i] = 256 - alpha[i];
+	  switch (this->dvdnav_color_spu) {
+	    case DVDNAV_SPU_YUV:
+	    case DVDNAV_SPU_YUY:
+	      cmap[i] = ((this->global_palette[packet->palette[i]] >> 16) & 0xff);	// Y
+	      cmap[i] = ((0x100-alpha[i])*cmap[i]) >> 8;
+	      cmapu[i] = ((this->global_palette[packet->palette[i]] >> 8) & 0xff);	// u
+	      cmapu[i] = ((0x100-alpha[i])*cmapu[i]) >> 8;
+	      cmapv[i] = ((this->global_palette[packet->palette[i]] >> 0) & 0xff);	// v
+	      cmapv[i] = ((0x100-alpha[i])*cmapv[i]) >> 8;
+	      break;
+	    case DVDNAV_SPU_RGB:
+	      ty = ((this->global_palette[packet->palette[i]] >> 16) & 0xff);	// Y
+              tu = ((this->global_palette[packet->palette[i]] >> 8) & 0xff);	// u
+              tv = ((this->global_palette[packet->palette[i]] >> 0) & 0xff);	// v
+	      spu_yuv_to_rgb(ty,tu,tv,&tr,&tg,&tb);
+	      cmap[i] = tr;							// Red
+	      cmapu[i] = tg;							// Green
+	      cmapv[i] = tb;							// Blue
+	      cmap[i] = ((0x100-alpha[i])*cmap[i]) >> 8;
+	      cmapu[i] = ((0x100-alpha[i])*cmapu[i]) >> 8;
+	      cmapv[i] = ((0x100-alpha[i])*cmapv[i]) >> 8;
+	      break;
+	    case DVDNAV_SPU_BGR:
+	      ty = ((this->global_palette[packet->palette[i]] >> 16) & 0xff);	// Y
+              tu = ((this->global_palette[packet->palette[i]] >> 8) & 0xff);	// u
+              tv = ((this->global_palette[packet->palette[i]] >> 0) & 0xff);	// v
+	      spu_yuv_to_rgb(ty,tu,tv,&tr,&tg,&tb);
+	      cmap[i] = tb;							// Blue
+	      cmapu[i] = tg;							// Green
+	      cmapv[i] = tr;							// Red
+	      cmap[i] = ((0x100-alpha[i])*cmap[i]) >> 8;
+	      cmapu[i] = ((0x100-alpha[i])*cmapu[i]) >> 8;
+	      cmapv[i] = ((0x100-alpha[i])*cmapv[i]) >> 8;
+	      break;
+	    }
+	  }
+      if (halpha[i] == 0) {hcmap[i] = 0; hcmapu[i] = 0; hcmapv[i] = 0;} else {
+        if (hcmap[i] + halpha[i] > 255)
+	  hcmap[i] = 256 - halpha[i];
+	  switch (this->dvdnav_color_spu) {
+	    case DVDNAV_SPU_YUV:
+	    case DVDNAV_SPU_YUY:
+              hcmap[i] = ((this->global_palette[thpalette[i]] >> 16) & 0xff);	// Y
+	      hcmap[i] = ((0x100-halpha[i])*hcmap[i]) >> 8;
+              hcmapu[i] = ((this->global_palette[thpalette[i]] >> 8) & 0xff);	// u
+	      hcmapu[i] = ((0x100-halpha[i])*hcmapu[i]) >> 8;
+              hcmapv[i] = ((this->global_palette[thpalette[i]] >> 0) & 0xff);	// v
+	      hcmapv[i] = ((0x100-halpha[i])*hcmapv[i]) >> 8;
+	      break;
+	    case DVDNAV_SPU_RGB:
+              ty = ((this->global_palette[thpalette[i]] >> 16) & 0xff);	// Y
+              tu = ((this->global_palette[thpalette[i]] >> 8) & 0xff);	// u
+              tv = ((this->global_palette[thpalette[i]] >> 0) & 0xff);	// v
+	      spu_yuv_to_rgb(ty,tu,tv,&tr,&tg,&tb);
+	      hcmap[i] = tr;
+	      hcmapu[i] = tg;
+	      hcmapv[i] = tb;
+	      hcmap[i] = ((0x100-halpha[i])*hcmap[i]) >> 8;
+	      hcmapu[i] = ((0x100-halpha[i])*hcmapu[i]) >> 8;
+	      hcmapv[i] = ((0x100-halpha[i])*hcmapv[i]) >> 8;
+	      break;
+	    case DVDNAV_SPU_BGR:
+              ty = ((this->global_palette[thpalette[i]] >> 16) & 0xff);	// Y
+              tu = ((this->global_palette[thpalette[i]] >> 8) & 0xff);	// u
+              tv = ((this->global_palette[thpalette[i]] >> 0) & 0xff);	// v
+	      spu_yuv_to_rgb(ty,tu,tv,&tr,&tg,&tb);
+	      hcmap[i] = tb;
+	      hcmapu[i] = tg;
+	      hcmapv[i] = tr;
+	      hcmap[i] = ((0x100-halpha[i])*hcmap[i]) >> 8;
+	      hcmapu[i] = ((0x100-halpha[i])*hcmapu[i]) >> 8;
+	      hcmapv[i] = ((0x100-halpha[i])*hcmapv[i]) >> 8;
+	      break;
+	    }
+	}
+      }
+}
   if (this->image_size < this->stride * this->height) {
     if (this->image != NULL) {
       free(this->image);
@@ -258,6 +537,58 @@
   }
   if (this->image == NULL)
     return;
+// Alloc 2nd image buffer (uv)
+if(this->dvdnav_menu && this->dvdnav_color_spu)
+  {
+  if (this->imageyuy)
+    {
+    free(this->imageyuy);
+    this->imageyuy=NULL;
+    this->aimageyuy=NULL;
+    }
+  if (this->dvdnav_color_spu==DVDNAV_SPU_YUV ||
+	this->dvdnav_color_spu==DVDNAV_SPU_YUY)
+    {
+    if (this->image_sizeuv < this->strideuv * this->heightuv)
+      {
+      if (this->imageu != NULL)
+        {
+        free(this->imageu);
+        this->image_sizeuv = 0;
+        }
+      this->imageu = malloc(3 * this->strideuv * this->heightuv);
+      if (this->imageu)
+        {
+        this->image_sizeuv = this->strideuv * this->heightuv;
+        this->imagev = this->imageu + this->image_sizeuv;
+        this->aimageuv = this->imagev + this->image_sizeuv;
+	}
+      }
+    memset(this->imageu,0,3 * this->strideuv * this->heightuv);
+    } else {
+    if (this->image_sizeuv < this->stride * this->height)
+      {
+      if (this->imageu != NULL)
+	{
+	free(this->imageu);
+	this->image_sizeuv = 0;
+        }
+      this->imageu = malloc(2 * this->stride * this->height);
+      if (this->imageu)
+        {
+        this->image_sizeuv = this->stride * this->height;
+        this->imagev = this->imageu + this->image_sizeuv;
+        this->aimageuv = this->imagev + this->image_sizeuv;
+	}
+      }
+    memset(this->imageu,0,2 * this->stride * this->height);
+    }
+  if (this->imageu == NULL) return;
+  } else {
+  if (this->imageu) free(this->imageu);
+  this->imageu=NULL;
+  this->image_sizeuv=0;
+  }
 
   /* Kludge: draw_alpha needs width multiple of 8. */
   if (this->width < this->stride)
@@ -292,8 +623,89 @@
     if (len > this->width - x || len == 0)
       len = this->width - x;
     /* FIXME have to use palette and alpha map*/
+//
+// Fill dvdnav menu area to image buffer
+//
+    if (this->dvdnav_menu)
+      {
+      if (this->start_row+y>=this->dvdnav_sy &&
+	    this->start_row+y<=this->dvdnav_ey)
+	{
+	if (this->start_col+x>=this->dvdnav_sx &&
+		this->start_col+x+len<=this->dvdnav_ex)
+	  spudec_process_fill(this,
+		    x,
+		    y,
+		    len,
+		    hcmap[color], hcmapu[color], hcmapv[color], halpha[color]);
+	else if(this->start_col+x<this->dvdnav_sx &&
+		this->start_col+x+len>this->dvdnav_sx &&
+		this->start_col+x+len<=this->dvdnav_ex)
+	  {
+	  spudec_process_fill(this,
+		    x,
+		    y,
+		    this->dvdnav_sx-this->start_col-x,
+		    cmap[color], cmapu[color], cmapv[color], alpha[color]);
+	  spudec_process_fill(this,
+		    this->dvdnav_sx-this->start_col,
+		    y,
+		    len+this->start_col+x-this->dvdnav_sx,
+		    hcmap[color], hcmapu[color], hcmapv[color], halpha[color]);
+	  }
+	else if(this->start_col+x<this->dvdnav_sx &&
+		this->start_col+x+len>this->dvdnav_sx &&
+		this->start_col+x+len>this->dvdnav_ex)
+	  {
+	  spudec_process_fill(this,
+		    x,
+		    y,
+		    this->dvdnav_sx-this->start_col-x,
+		    cmap[color], cmapu[color], cmapv[color], alpha[color]);
+	  spudec_process_fill(this,
+		    this->dvdnav_sx-this->start_col,
+		    y,
+		    this->dvdnav_ex-this->dvdnav_sx,
+		    hcmap[color], hcmapu[color], hcmapv[color], halpha[color]);
+	  spudec_process_fill(this,
+		    this->dvdnav_ex-this->start_col,
+		    y,
+		    x+len+this->start_col-this->dvdnav_ex,
+		    cmap[color], cmapu[color], cmapv[color], alpha[color]);
+	  }
+	else if(this->start_col+x>=this->dvdnav_sx &&
+		this->start_col+x<this->dvdnav_ex &&
+		this->start_col+x+len>this->dvdnav_ex)
+	  {
+	  spudec_process_fill(this,
+		    x,
+		    y,
+		    this->dvdnav_ex-this->start_col-x,
+		    hcmap[color], hcmapu[color], hcmapv[color], halpha[color]);
+	  spudec_process_fill(this,
+		    this->dvdnav_ex-this->start_col,
+		    y,
+		    len+this->start_col+x-this->dvdnav_ex,
+		    cmap[color], cmapu[color], cmapv[color], alpha[color]);
+	  }
+	  else
+	  spudec_process_fill(this,
+		    x,
+		    y,
+		    len,
+		    cmap[color], cmapu[color], cmapv[color], alpha[color]);
+	} else
+	spudec_process_fill(this,
+		    x,
+		    y,
+		    len,
+		    cmap[color], cmapu[color], cmapv[color], alpha[color]);
+      }
+      else
+      {
     memset(this->image + y * this->stride + x, cmap[color], len);
     memset(this->aimage + y * this->stride + x, alpha[color], len);
+      }
     x += len;
     if (x >= this->width) {
       next_line(packet);
@@ -301,7 +713,12 @@
       ++y;
     }
   }
+  packet->control_start = control_start;
+  packet->current_nibble[0]=current_nibble[0];
+  packet->current_nibble[1]=current_nibble[1];
+  packet->deinterlace_oddness=deinterlace_oddness;
   spudec_cut_image(this);
+//printf("spudec_process_data: w: %i h: %i end\n",this->height,this->width);
 }
 
 
@@ -316,6 +733,7 @@
 {
   int used[16],i,cused,start,step,color;
 
+//printf("spudec:c1      ");for(i=0;i<16;i++) printf("%x ",this->global_palette[i]); printf("\n");
   memset(used, 0, sizeof(used));
   for (i=0; i<4; i++)
     if (packet->alpha[i]) /* !Transparent? */
@@ -339,6 +757,7 @@
        start += step;
     }
   }
+//printf("spudec:c2      ");for(i=0;i<16;i++) printf("%x ",this->global_palette[i]); printf("\n");
 }
 
 static void spudec_process_control(spudec_handle_t *this, unsigned int pts100)
@@ -586,6 +1005,7 @@
   spu->now_pts = 0;
   spu->end_pts = 0;
   spu->packet_size = spu->packet_offset = 0;
+//  if (spu->last_packet) {printf("free4\n");spudec_free_packet(spu->last_packet); spu->last_packet=NULL;}
 }
 
 void spudec_heartbeat(void *this, unsigned int pts100)
@@ -593,13 +1013,22 @@
   spudec_handle_t *spu = (spudec_handle_t*) this;
   spu->now_pts = pts100;
 
+  if(spu->queue_head) spu->queue_head->start_pts=0;
   while (spu->queue_head != NULL && pts100 >= spu->queue_head->start_pts) {
     packet_t *packet = spudec_dequeue_packet(spu);
     spu->start_pts = packet->start_pts;
     spu->end_pts = packet->end_pts;
-    if (spu->auto_palette)
+    if (spu->auto_palette && !spu->dvdnav_menu)
       compute_palette(spu, packet);
     spudec_process_data(spu, packet);
+    if (spu->dvdnav_menu)
+      {
+      if(spu->last_packet)
+	{
+	spudec_free_packet(spu->last_packet);
+	}
+      spu->last_packet=packet;
+      } else
     spudec_free_packet(packet);
     spu->spu_changed = 1;
   }
@@ -605,12 +1034,18 @@
   }
 }
 
+
 int spudec_visible(void *this){
     spudec_handle_t *spu = (spudec_handle_t *)this;
+    if(!spu) return 0;
+    if (spu->dvdnav_menu && spu->height > 0)
+      {
+      if(spu->height>0) spu->end_pts=UINT_MAX;
+      return 1;
+      }
     int ret=(spu->start_pts <= spu->now_pts &&
 	     spu->now_pts < spu->end_pts &&
 	     spu->height > 0);
-//    printf("spu visible: %d  \n",ret);
     return ret;
 }
 
@@ -622,12 +1057,102 @@
   }
 }
 
-void spudec_draw(void *this, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride))
+void spudec_draw(void *this, void (*draw_alpha)(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride))
 {
     spudec_handle_t *spu = (spudec_handle_t *)this;
     if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts && spu->image)
     {
-	draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height,
+    if (spu->dvdnav_menu)
+      {	/* spu menu mode? */
+      switch (spu->dvdnav_color_spu)
+	{
+//
+// Draw spu menu Y,u and v planes in YUV mode
+//
+	case DVDNAV_SPU_YUV:
+	  draw_alpha(spu->start_col,
+		    spu->start_row,
+		    spu->width,
+		    spu->height,
+		    DEST_PLANES_Y,
+		    spu->image,
+		    spu->aimage,
+		    spu->stride);
+	  draw_alpha(spu->start_coluv,
+		    spu->start_rowuv,
+		    spu->widthuv,
+		    spu->heightuv,
+		    DEST_PLANES_U,
+		    spu->imageu,
+		    spu->aimageuv,
+		    spu->strideuv);
+	  draw_alpha(spu->start_coluv,
+		    spu->start_rowuv,
+		    spu->widthuv,
+		    spu->heightuv,
+		    DEST_PLANES_V,
+		    spu->imagev,
+		    spu->aimageuv,
+		    spu->strideuv);
+	  break;
+//
+// Draw spu menu all planes in YUY mode
+//
+	case DVDNAV_SPU_YUY:
+	  if (!spu->imageyuy) spudec_create_yuy(spu,0);
+	  if (spu->imageyuy) draw_alpha(spu->start_col,
+		    spu->start_row,
+		    spu->width*2,
+		    spu->height/2,
+		    DEST_PLANES_YUYV,
+		    spu->imageyuy,
+		    spu->aimageyuy,
+		    spu->strideyuy);
+	  break;
+//
+// Draw spu menu Red,Blue and Green on RGB or BGR mode
+//
+	case DVDNAV_SPU_RGB:
+	case DVDNAV_SPU_BGR:
+	  draw_alpha(spu->start_col,
+		    spu->start_row,
+		    spu->width, spu->height,
+		    DEST_PLANES_BR,
+		    spu->imagev,
+		    spu->aimage,
+		    spu->stride);
+	  draw_alpha(spu->start_col,
+		    spu->start_row,
+		    spu->width,
+		    spu->height,
+		    DEST_PLANES_G,
+		    spu->imageu,
+		    spu->aimage,
+		    spu->stride);
+	  draw_alpha(spu->start_col,
+		    spu->start_row,
+		    spu->width,
+		    spu->height,
+		    DEST_PLANES_RB,
+		    spu->image,
+		    spu->aimage,
+		    spu->stride);
+	  break;
+//
+// Draw spu menu Y planes in normal mode
+//
+	default:
+	  draw_alpha(spu->start_col,
+		    spu->start_row,
+		    spu->width,
+		    spu->height,
+		    DEST_PLANES_Y,
+		    spu->image,
+		    spu->aimage,
+		    spu->stride);
+	}
+      } else
+	draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height,DEST_PLANES_Y,
 		   spu->image, spu->aimage, spu->stride);
 	spu->spu_changed = 0;
     }
@@ -737,6 +1262,125 @@
   }
 }
 
+//
+// bilinear scale: u and v planes
+//
+static void scale_image_uv(int x, int y, scale_pixel* table_x,
+	scale_pixel* table_y, spudec_handle_t * spu)
+{
+  int alpha[4];
+  int coloru[4];
+  int colorv[4];
+  unsigned int scale[4];
+  int base = table_y[y].position * spu->strideuv + table_x[x].position;
+  int scaled = y * spu->scaled_strideuv + x;
+  alpha[0] = canon_alpha(spu->aimageuv[base]);
+  alpha[1] = canon_alpha(spu->aimageuv[base + 1]);
+  alpha[2] = canon_alpha(spu->aimageuv[base + spu->strideuv]);
+  alpha[3] = canon_alpha(spu->aimageuv[base + spu->strideuv + 1]);
+  coloru[0] = spu->imageu[base];
+  coloru[1] = spu->imageu[base + 1];
+  coloru[2] = spu->imageu[base + spu->strideuv];
+  coloru[3] = spu->imageu[base + spu->strideuv + 1];
+  colorv[0] = spu->imagev[base];
+  colorv[1] = spu->imagev[base + 1];
+  colorv[2] = spu->imagev[base + spu->strideuv];
+  colorv[3] = spu->imagev[base + spu->strideuv + 1];
+// FIXME: color hack!!!
+//  scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
+//  scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
+//  scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
+//  scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
+  scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * 0x100;
+  scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * 0x100;
+  scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * 0x100;
+  scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * 0x100;
+  spu->scaled_imageu[scaled] =
+	(coloru[0] * scale[0] +
+	coloru[1] * scale[1] +
+	coloru[2] * scale[2] +
+	coloru[3] * scale[3])>>24;
+  spu->scaled_imagev[scaled] =
+	(colorv[0] * scale[0] +
+	colorv[1] * scale[1] +
+	colorv[2] * scale[2] +
+	colorv[3] * scale[3])>>24;
+  scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
+  scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
+  scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
+  scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
+  spu->scaled_aimageuv[scaled] =
+	(scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
+  if (spu->scaled_aimageuv[scaled]){
+    spu->scaled_aimageuv[scaled] = 256 - spu->scaled_aimageuv[scaled];
+    if(spu->scaled_aimageuv[scaled] + spu->scaled_imageu[scaled] > 255)
+      spu->scaled_imageu[scaled] = 256 - spu->scaled_aimageuv[scaled];
+    if(spu->scaled_aimageuv[scaled] + spu->scaled_imagev[scaled] > 255)
+      spu->scaled_imagev[scaled] = 256 - spu->scaled_aimageuv[scaled];
+  }
+}
+
+//
+// bilinear scale: Red, Green and Blue planes
+//
+static void scale_image_rgb(int x, int y, scale_pixel* table_x, scale_pixel* table_y, spudec_handle_t * spu)
+{
+  int alpha[4];
+  int colorr[4];
+  int colorg[4];
+  int colorb[4];
+  unsigned int scale[4];
+  int base = table_y[y].position * spu->stride + table_x[x].position;
+  int scaled = y * spu->scaled_stride + x;
+  alpha[0] = canon_alpha(spu->aimage[base]);
+  alpha[1] = canon_alpha(spu->aimage[base + 1]);
+  alpha[2] = canon_alpha(spu->aimage[base + spu->stride]);
+  alpha[3] = canon_alpha(spu->aimage[base + spu->stride + 1]);
+  colorr[0] = spu->image[base];
+  colorr[1] = spu->image[base + 1];
+  colorr[2] = spu->image[base + spu->stride];
+  colorr[3] = spu->image[base + spu->stride + 1];
+  colorg[0] = spu->imageu[base];
+  colorg[1] = spu->imageu[base + 1];
+  colorg[2] = spu->imageu[base + spu->stride];
+  colorg[3] = spu->imageu[base + spu->stride + 1];
+  colorb[0] = spu->imagev[base];
+  colorb[1] = spu->imagev[base + 1];
+  colorb[2] = spu->imagev[base + spu->stride];
+  colorb[3] = spu->imagev[base + spu->stride + 1];
+  scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
+  scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
+  scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
+  scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
+  spu->scaled_image[scaled] =
+	(colorr[0] * scale[0] +
+	colorr[1] * scale[1] +
+	colorr[2] * scale[2] +
+	colorr[3] * scale[3])>>24;
+  spu->scaled_imageu[scaled] =
+	(colorg[0] * scale[0] +
+	colorg[1] * scale[1] +
+	colorg[2] * scale[2] +
+	colorg[3] * scale[3])>>24;
+  spu->scaled_imagev[scaled] =
+	(colorb[0] * scale[0] +
+	colorb[1] * scale[1] +
+	colorb[2] * scale[2] +
+	colorb[3] * scale[3])>>24;
+  spu->scaled_aimage[scaled] =
+	(scale[0] + scale[1] + scale[2] + scale[3]) >> 16;
+  if (spu->scaled_aimage[scaled]){
+    spu->scaled_aimage[scaled] = 256 - spu->scaled_aimage[scaled];
+    if(spu->scaled_aimage[scaled] + spu->scaled_image[scaled] > 255)
+      spu->scaled_image[scaled] = 256 - spu->scaled_aimage[scaled];
+    if(spu->scaled_aimage[scaled] + spu->scaled_imageu[scaled] > 255)
+      spu->scaled_imageu[scaled] = 256 - spu->scaled_aimage[scaled];
+    if(spu->scaled_aimage[scaled] + spu->scaled_imagev[scaled] > 255)
+      spu->scaled_imagev[scaled] = 256 - spu->scaled_aimage[scaled];
+  }
+}
+
+
 void sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh, int ds,
 	unsigned char *s1, unsigned char *s2, int sw, int sh, int ss)
 {
@@ -763,68 +1407,358 @@
 	sws_freeContext(ctx);
 }
 
-void spudec_draw_scaled(void *me, unsigned int dxs, unsigned int dys, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride))
+//
+// Convert Yuv image to YuY image
+//
+void spudec_create_yuy(void *this, int spu_scaled)
+{
+spudec_handle_t *spu = this;
+unsigned char *dptr;
+unsigned char *daptr;
+unsigned char *sptry;
+unsigned char *sptru;
+unsigned char *sptrv;
+unsigned char *saptr;
+unsigned char *saptruv;
+int y,x;
+
+if (spu_scaled) {
+  spu->strideyuy=spu->scaled_stride*2;
+  spu->imageyuy=malloc(spu->strideyuy*(spu->height+2)*2);
+  memset(spu->imageyuy,0,spu->strideyuy*(spu->height+2)*2);
+  spu->aimageyuy=spu->imageyuy+spu->strideyuy*spu->scaled_height;
+  for(y=0;y<spu->scaled_height;y++) {
+    dptr=spu->imageyuy+y*spu->strideyuy;
+    daptr=spu->aimageyuy+y*spu->strideyuy;
+    sptry=spu->scaled_image+y*spu->scaled_stride;
+    sptru=spu->scaled_imageu+y/2*spu->scaled_strideuv;
+    sptrv=spu->scaled_imagev+y/2*spu->scaled_strideuv;
+    saptr=spu->scaled_aimage+y*spu->scaled_stride;
+    saptruv=spu->scaled_aimageuv+y/2*spu->scaled_strideuv;
+    for(x=0;x<spu->scaled_widthuv-1;x++) {
+      *dptr++=*sptry++;
+      *dptr++=*sptrv++;
+      *dptr++=*sptry++;
+      *dptr++=*sptru++;
+      *daptr++=*saptr++;
+      *daptr++=*saptruv;
+      *daptr++=*saptr++;
+      *daptr++=*saptruv++;
+      } }
+  } else {
+  spu->strideyuy=spu->stride*2;
+  spu->imageyuy=malloc(spu->strideyuy*(spu->height+2)*2);
+  memset(spu->imageyuy,0,spu->strideyuy*(spu->height+2)*2);
+  spu->aimageyuy=spu->imageyuy+spu->strideyuy*spu->height;
+  for(y=0;y<spu->height;y++) {
+    dptr=spu->imageyuy+y*spu->strideyuy;
+    daptr=spu->aimageyuy+y*spu->strideyuy;
+    sptry=spu->image+y*spu->stride;
+    sptru=spu->imageu+y/2*spu->strideuv;
+    sptrv=spu->imagev+y/2*spu->strideuv;
+    saptr=spu->aimage+y*spu->stride;
+    saptruv=spu->aimageuv+y/2*spu->strideuv;
+    for(x=0;x<spu->widthuv-1;x++) {
+      *dptr++=*sptry++;
+      *dptr++=*sptrv++;
+      *dptr++=*sptry++;
+      *dptr++=*sptru++;
+      *daptr++=*saptr++;
+      *daptr++=*saptruv;
+      *daptr++=*saptr++;
+      *daptr++=*saptruv++;
+      } }
+  }
+}
+
+//
+// Sws scale: u and v planes
+//
+void sws_spu_image_uv(unsigned char *du, unsigned char *dv, unsigned char *d2,
+	int dw, int dh, int ds, unsigned char *su, unsigned char *sv,
+	unsigned char *s2, int sw, int sh, int ss)
+{
+struct SwsContext *ctx;
+static SwsFilter filter;
+static int firsttime = 1;
+static float oldvar;
+int i;
+
+if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH);
+if (firsttime)
+    {
+    filter.lumH = filter.lumV =
+	filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0);
+    sws_normalizeVec(filter.lumH, 1.0);
+    firsttime = 0;
+    oldvar = spu_gaussvar;
+    }
+
+ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL);
+sws_scale(ctx,&su,&ss,0,sh,&du,&ds);
+sws_scale(ctx,&sv,&ss,0,sh,&dv,&ds);
+for (i=ss*sh-1; i>=0; i--)
+  if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
+sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds);
+for (i=ds*dh-1; i>=0; i--)
+  if (d2[i]==0) d2[i] = 1;
+  else if (d2[i]==255) d2[i] = 0;
+sws_freeContext(ctx);
+}
+
+//
+// Sws scale: Red, Green and Blue planes
+//
+void sws_spu_image_rgb(unsigned char *dr, unsigned char *dg, unsigned char *db,
+	unsigned char *d2, int dw, int dh, int ds,
+	unsigned char *sr,unsigned char *sg,unsigned char *sb,
+	unsigned char *s2, int sw, int sh, int ss)
+{
+struct SwsContext *ctx;
+static SwsFilter filter;
+static int firsttime = 1;
+static float oldvar;
+int i;
+
+if (!firsttime && oldvar != spu_gaussvar) sws_freeVec(filter.lumH);
+if (firsttime)
+    {
+    filter.lumH = filter.lumV =
+	filter.chrH = filter.chrV = sws_getGaussianVec(spu_gaussvar, 3.0);
+    sws_normalizeVec(filter.lumH, 1.0);
+    firsttime = 0;
+    oldvar = spu_gaussvar;
+    }
+
+ctx=sws_getContext(sw, sh, PIX_FMT_GRAY8, dw, dh, PIX_FMT_GRAY8, SWS_GAUSS, &filter, NULL, NULL);
+sws_scale(ctx,&sr,&ss,0,sh,&dr,&ds);
+sws_scale(ctx,&sg,&ss,0,sh,&dg,&ds);
+sws_scale(ctx,&sb,&ss,0,sh,&db,&ds);
+for (i=ss*sh-1; i>=0; i--) if (!s2[i]) s2[i] = 255; //else s2[i] = 1;
+sws_scale(ctx,&s2,&ss,0,sh,&d2,&ds);
+for (i=ds*dh-1; i>=0; i--)
+    if (d2[i]==0) d2[i] = 1;
+    else if (d2[i]==255) d2[i] = 0;
+sws_freeContext(ctx);
+}
+
+//
+// Enable/disable dvdmenu mode, and set color mode
+//	cflg = 0:	Y SPU
+//	cflg = 1:	YUV SPU
+//	cflg = 2:	RGB SPU
+//	cflg = 3:	BGR SPU
+//	cflg = 4:	YUY SPU
+//
+void spudec_dvdnav_mode(void *this, int mode, int cflg)
+{		/* set/clear spu menu mode */
+spudec_handle_t *spu = (spudec_handle_t *)this;
+if (!spu) return;
+spu->dvdnav_menu=mode;
+if (mode)
+    spu->dvdnav_color_spu=cflg;
+    else
+    spu->dvdnav_color_spu=0;
+if (!spu->dvdnav_menu && spu->last_packet)
+  {
+  spudec_free_packet(spu->last_packet);
+  spu->last_packet=NULL;
+  }
+return;
+}
+
+//
+// Set dvd menu button draw area and palette
+//
+void spudec_dvdnav_area(void *this, uint16_t sx, uint16_t sy, uint16_t ex,
+	uint16_t ey, uint32_t palette)
+{
+spudec_handle_t *spu = this;
+if (!spu) return;
+if (spu->dvdnav_sx==FFMIN(sx,ex) &&
+	spu->dvdnav_ex==FFMAX(sx,ex) &&
+	spu->dvdnav_sy==FFMIN(sy,ey) &&
+	spu->dvdnav_ey==FFMAX(sy,ey) &&
+	spu->dvdnav_palette==palette) return;
+spu->dvdnav_sx=FFMIN(sx,ex);		/* set spu button area, palette & on */
+spu->dvdnav_ex=FFMAX(sx,ex);
+spu->dvdnav_sy=FFMIN(sy,ey);
+spu->dvdnav_ey=FFMAX(sy,ey);
+spu->dvdnav_palette=palette;
+spu->dvdnav_modify=1;
+if (spu->dvdnav_menu && spu->last_packet)
+  {
+//  if (spu->auto_palette)
+//    compute_palette(spu, spu->last_packet);
+  spudec_process_data(spu, spu->last_packet);
+  }
+return;
+}
+
+//
+// Set dvd menu button palette
+//
+void spudec_dvdnav_palette(void *this, uint32_t palette)
+{
+spudec_handle_t *spu = this;
+if (!spu) return;
+spu->dvdnav_palette=palette;		/* set spu button palette */
+return;
+}
+
+//
+// Draw scaled image in YUV and YUY mode
+//	Note: expanded spudec_draw_scale with half size uv planes
+//
+void spudec_draw_scaled_yuv(void *me, unsigned int dxs, unsigned int dys,
+	void (*draw_alpha)(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride))
 {
   spudec_handle_t *spu = (spudec_handle_t *)me;
   scale_pixel *table_x;
   scale_pixel *table_y;
+  unsigned int scalex = 0;
+  unsigned int scaley = 0;
 
   if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts) {
 
     // check if only forced subtitles are requested 
     if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){ 
-	return;
-    }
+	return;}
 
-    if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
-	|| (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
+    if (!(spu_aamode&16) && (spu->orig_frame_width == 0 ||
+	    spu->orig_frame_height == 0 ||
+	    (spu->orig_frame_width == dxs && spu->orig_frame_height == dys)))
+{
       if (spu->image)
       {
-	draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height,
-		   spu->image, spu->aimage, spu->stride);
-	spu->spu_changed = 0;
+	if (spu->dvdnav_color_spu==DVDNAV_SPU_YUY) {
+	  if (!spu->imageyuy) spudec_create_yuy(spu,0);
+	  if (spu->imageyuy) draw_alpha(spu->start_col,
+		    spu->start_row,
+		    spu->width*2,
+		    spu->heightuv*2,
+		    DEST_PLANES_YUYV,
+		    spu->imageyuy,
+		    spu->aimageyuy,
+		    spu->strideyuy);
+	  } else {
+	  draw_alpha(spu->start_col,
+		    spu->start_row,
+		    spu->width,
+		    spu->height,
+		    DEST_PLANES_Y,
+		    spu->image,
+		    spu->aimage,
+		    spu->stride);
+	  if(spu->dvdnav_color_spu && spu->imageu && spu->aimageuv)
+	    draw_alpha(spu->start_coluv,
+		    spu->start_rowuv,
+		    spu->widthuv,
+		    spu->heightuv,
+		    DEST_PLANES_U,
+		    spu->imageu,
+		    spu->aimageuv,
+		    spu->strideuv);
+	  if(spu->dvdnav_color_spu && spu->imagev && spu->aimageuv)
+	    draw_alpha(spu->start_coluv,
+		    spu->start_rowuv,
+		    spu->widthuv,
+		    spu->heightuv,
+		    DEST_PLANES_V,
+		    spu->imagev,
+		    spu->aimageuv,
+		    spu->strideuv);
       }
+	spu->spu_changed = 0;
     }
-    else {
-      if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) {	/* Resizing is needed */
+    } else {
+      if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys)
+	{	/* Resizing is needed */
 	/* scaled_x = scalex * x / 0x100
 	   scaled_y = scaley * y / 0x100
 	   order of operations is important because of rounding. */
-	unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
-	unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
+	scalex = 0x100 * dxs / spu->orig_frame_width;
+	scaley = 0x100 * dys / spu->orig_frame_height;
+
 	spu->scaled_start_col = spu->start_col * scalex / 0x100;
 	spu->scaled_start_row = spu->start_row * scaley / 0x100;
 	spu->scaled_width = spu->width * scalex / 0x100;
 	spu->scaled_height = spu->height * scaley / 0x100;
+	spu->scaled_start_coluv = spu->start_coluv * scalex / 0x100;
+	spu->scaled_start_rowuv = spu->start_rowuv * scaley / 0x100;
+	spu->scaled_widthuv = spu->widthuv * scalex / 0x100;
+	spu->scaled_heightuv = spu->heightuv * scaley / 0x100;
 	/* Kludge: draw_alpha needs width multiple of 8 */
 	spu->scaled_stride = (spu->scaled_width + 7) & ~7;
-	if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) {
-	  if (spu->scaled_image) {
+	spu->scaled_strideuv = (spu->scaled_widthuv + 7) & ~7;
+	if (spu->scaled_image_size < spu->scaled_stride *
+		(spu->scaled_height+2))
+{
+	  if (spu->scaled_image)
+	    {
 	    free(spu->scaled_image);
 	    spu->scaled_image_size = 0;
 	  }
-	  spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height);
-	  if (spu->scaled_image) {
-	    spu->scaled_image_size = spu->scaled_stride * spu->scaled_height;
+	  spu->scaled_image = malloc(2 * spu->scaled_stride *
+		(spu->scaled_height+2));
+	  if (spu->scaled_image)
+{
+	    memset(spu->scaled_image,0,
+		    2 * spu->scaled_stride * (spu->scaled_height+2));
+	    spu->scaled_image_size = spu->scaled_stride *
+		    (spu->scaled_height+2);
 	    spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size;
 	  }
 	}
+	if (spu->scaled_image_sizeuv < spu->scaled_strideuv *
+		(spu->scaled_heightuv+2))
+{
+	  if (spu->scaled_imageu)
+	    {
+	    free(spu->scaled_imageu);
+	    spu->scaled_image_sizeuv = 0;
+    }
+	  spu->scaled_imageu = malloc(3 * spu->scaled_strideuv *
+		(spu->scaled_height+2));
+	  if (spu->scaled_imageu)
+	    {
+	    memset(spu->scaled_imageu,0,3 * spu->scaled_strideuv *
+		    (spu->scaled_height+2));
+	    spu->scaled_image_sizeuv = spu->scaled_strideuv *
+		    (spu->scaled_heightuv+2);
+	    spu->scaled_imagev = spu->scaled_imageu +
+		    spu->scaled_image_sizeuv;
+	    spu->scaled_aimageuv = spu->scaled_imagev +
+		    spu->scaled_image_sizeuv;
+    }
+	}
 	if (spu->scaled_image) {
 	  unsigned int x, y;
 	  if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
 	    goto nothing_to_do;
 	  }
-	  switch(spu_aamode&15) {
+	  if (spu->scaled_widthuv <= 1 || spu->scaled_heightuv <= 1) {
+	    goto nothing_to_do;
+	    }
+	switch(spu_aamode&15)
+	  {
 	  case 4:
 	  sws_spu_image(spu->scaled_image, spu->scaled_aimage,
 		  spu->scaled_width, spu->scaled_height, spu->scaled_stride,
 		  spu->image, spu->aimage, spu->width, spu->height, spu->stride);
+	    sws_spu_image_uv(spu->scaled_imageu, spu->scaled_imagev,
+		  spu->scaled_aimageuv, spu->scaled_widthuv,
+		  spu->scaled_heightuv, spu->scaled_strideuv,
+		  spu->imageu, spu->imagev, spu->aimageuv,
+		  spu->widthuv, spu->heightuv, spu->strideuv);
 	  break;
 	  case 3:
 	  table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
 	  table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
-	  if (!table_x || !table_y) {
-	    mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n");
+	    if (!table_x || !table_y)
+	      {
+	      mp_msg(MSGT_SPUDEC, MSGL_FATAL,
+		    "Fatal: spudec_draw_scaled: calloc failed\n");
 	  }
 	  scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x);
 	  scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y);
@@ -833,17 +1767,52 @@
 	      scale_image(x, y, table_x, table_y, spu);
 	  free(table_x);
 	  free(table_y);
+	    table_x = calloc(spu->scaled_widthuv, sizeof(scale_pixel));
+	    table_y = calloc(spu->scaled_heightuv, sizeof(scale_pixel));
+	    if (!table_x || !table_y) {
+	      mp_msg(MSGT_SPUDEC, MSGL_FATAL,
+		    "Fatal: spudec_draw_scaled: calloc failed\n");
+	      }
+	    scale_table(0, 0, spu->widthuv - 1, spu->scaled_widthuv - 1,
+		table_x);
+	    scale_table(0, 0, spu->heightuv - 1, spu->scaled_heightuv - 1,
+		table_y);
+	    for (y = 0; y < spu->scaled_heightuv; y++)
+	      for (x = 0; x < spu->scaled_widthuv; x++)
+		scale_image_uv(x, y, table_x, table_y, spu);
+	    free(table_x);
+	    free(table_y);
 	  break;
 	  case 0:
 	  /* no antialiasing */
-	  for (y = 0; y < spu->scaled_height; ++y) {
+	  for (y = 0; y < spu->scaled_height; ++y)
+	    {
 	    int unscaled_y = y * 0x100 / scaley;
 	    int strides = spu->stride * unscaled_y;
 	    int scaled_strides = spu->scaled_stride * y;
-	    for (x = 0; x < spu->scaled_width; ++x) {
+	    for (x = 0; x < spu->scaled_width; ++x)
+	      {
 	      int unscaled_x = x * 0x100 / scalex;
-	      spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x];
-	      spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x];
+	      spu->scaled_image[scaled_strides + x] =
+		    spu->image[strides + unscaled_x];
+	      spu->scaled_aimage[scaled_strides + x] =
+		    spu->aimage[strides + unscaled_x];
+	      }
+	    }
+	  for (y = 0; y < spu->scaled_heightuv; ++y)
+	    {
+	    int unscaled_y = y * 0x100 / scaley;
+	    int strides = spu->strideuv * unscaled_y;
+	    int scaled_strides = spu->scaled_strideuv * y;
+	    for (x = 0; x < spu->scaled_widthuv; ++x)
+	      {
+	      int unscaled_x = x * 0x100 / scalex;
+	      spu->scaled_imageu[scaled_strides + x] =
+		    spu->imageu[strides + unscaled_x];
+	      spu->scaled_imagev[scaled_strides + x] =
+		    spu->imagev[strides + unscaled_x];
+	      spu->scaled_aimageuv[scaled_strides + x] =
+		    spu->aimageuv[strides + unscaled_x];
 	    }
 	  }
 	  break;
@@ -851,13 +1820,18 @@
 	  {
 	    /* Intermediate antialiasing. */
 	    for (y = 0; y < spu->scaled_height; ++y) {
-	      const unsigned int unscaled_top = y * spu->orig_frame_height / dys;
-	      unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys;
+	      const unsigned int unscaled_top =
+		    y * spu->orig_frame_height / dys;
+	      unsigned int unscaled_bottom =
+		    (y + 1) * spu->orig_frame_height / dys;
 	      if (unscaled_bottom >= spu->height)
 		unscaled_bottom = spu->height - 1;
-	      for (x = 0; x < spu->scaled_width; ++x) {
-		const unsigned int unscaled_left = x * spu->orig_frame_width / dxs;
-		unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs;
+	      for (x = 0; x < spu->scaled_width; ++x)
+	        {
+		const unsigned int unscaled_left =
+			x * spu->orig_frame_width / dxs;
+		unsigned int unscaled_right =
+			(x + 1) * spu->orig_frame_width / dxs;
 		unsigned int color = 0;
 		unsigned int alpha = 0;
 		unsigned int walkx, walky;
@@ -865,7 +1839,8 @@
 		if (unscaled_right >= spu->width)
 		  unscaled_right = spu->width - 1;
 		for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
-		  for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) {
+		  for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx)
+		    {
 		    base = walky * spu->stride + walkx;
 		    tmp = canon_alpha(spu->aimage[base]);
 		    alpha += tmp;
@@ -874,7 +1849,8 @@
 		base = y * spu->scaled_stride + x;
 		spu->scaled_image[base] = alpha ? color / alpha : 0;
 		spu->scaled_aimage[base] =
-		  alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left);
+		  alpha * (1 + unscaled_bottom - unscaled_top) *
+		  (1 + unscaled_right - unscaled_left);
 		/* spu->scaled_aimage[base] =
 		  alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
 		if (spu->scaled_aimage[base]) {
@@ -884,6 +1860,51 @@
 		}
 	      }
 	    }
+	    for (y = 0; y < spu->scaled_heightuv; ++y) {
+	      const unsigned int unscaled_top = y *
+		    (spu->orig_frame_height/2) / (dys/2);
+	      unsigned int unscaled_bottom = (y + 1) *
+		    (spu->orig_frame_height/2) / (dys/2);
+	      if (unscaled_bottom >= spu->heightuv)
+		unscaled_bottom = spu->heightuv - 1;
+	      for (x = 0; x < spu->scaled_widthuv; ++x) {
+		const unsigned int unscaled_left = x *
+			(spu->orig_frame_width/2) / (dxs/2);
+		unsigned int unscaled_right = (x + 1) *
+			(spu->orig_frame_width/2) / (dxs/2);
+		unsigned int coloru = 0;
+		unsigned int colorv = 0;
+		unsigned int alpha = 0;
+		unsigned int walkx, walky;
+		unsigned int base, tmp;
+		if (unscaled_right >= spu->widthuv)
+		  unscaled_right = spu->widthuv - 1;
+		for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
+		  for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx)
+		    {
+		    base = walky * spu->strideuv + walkx;
+		    tmp = canon_alpha(spu->aimageuv[base]);
+		    alpha += tmp;
+		    coloru += tmp * spu->imageu[base];
+		    colorv += tmp * spu->imagev[base];
+		    }
+		base = y * spu->scaled_strideuv + x;
+		spu->scaled_imageu[base] = alpha ? coloru / alpha : 0;
+		spu->scaled_imagev[base] = alpha ? colorv / alpha : 0;
+		spu->scaled_aimageuv[base] =
+		  alpha * (1 + unscaled_bottom - unscaled_top) *
+		  (1 + unscaled_right - unscaled_left);
+		/* spu->scaled_aimage[base] =
+		  alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
+		if (spu->scaled_aimageuv[base]) {
+		  spu->scaled_aimageuv[base] = 256 - spu->scaled_aimageuv[base];
+		  if (spu->scaled_aimageuv[base] + spu->scaled_imageu[base] > 255)
+		    spu->scaled_imageu[base] = 256 - spu->scaled_aimageuv[base];
+		  if (spu->scaled_aimageuv[base] + spu->scaled_imagev[base] > 255)
+		    spu->scaled_imagev[base] = 256 - spu->scaled_aimageuv[base];
+		}
+	      }
+	    }
 	  }
 	  break;
 	  case 2:
@@ -943,7 +1964,8 @@
 	      for (x = 0; x < spu->scaled_width; ++x) {
 		const double unscaled_x = x * inv_scalex;
 		const double unscaled_x_right = unscaled_x + inv_scalex;
-		const unsigned int left_right_column = FFMIN(unscaled_x_right, unscaled_x + 1.0);
+		const unsigned int left_right_column =
+			FFMIN(unscaled_x_right, unscaled_x + 1.0);
 		const double left = left_right_column - unscaled_x;
 		const unsigned int width = unscaled_x_right > left_right_column
 		  ? (unsigned int) unscaled_x_right - left_right_column
@@ -964,13 +1986,17 @@
 		*/
 		/* 1: top left part */
 		base = spu->stride * (unsigned int) unscaled_y;
-		tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
+		tmp = left * top *
+		    canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
 		alpha += tmp;
 		color += tmp * spu->image[base + (unsigned int) unscaled_x];
 		/* 2: top center part */
 		if (width > 0) {
 		  unsigned int walkx;
-		  for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
+		  for (walkx = left_right_column;
+			walkx < (unsigned int) unscaled_x_right;
+			++walkx)
+		    {
 		    base = spu->stride * (unsigned int) unscaled_y + walkx;
 		    tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]);
 		    alpha += tmp;
@@ -979,7 +2005,1070 @@
 		}
 		/* 3: top right part */
 		if (right > 0.0) {
-		  base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right;
+		  base = spu->stride * (unsigned int) unscaled_y +
+			(unsigned int) unscaled_x_right;
+		  tmp = right * top * canon_alpha(spu->aimage[base]);
+		  alpha += tmp;
+		  color += tmp * spu->image[base];
+		}
+		/* 4: center left part */
+		if (height > 0) {
+		  unsigned int walky;
+		  for (walky = top_low_row;
+			walky < (unsigned int) unscaled_y_bottom;
+			++walky)
+		    {
+		    base = spu->stride * walky + (unsigned int) unscaled_x;
+		    tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]);
+		    alpha += tmp;
+		    color += tmp * spu->image[base];
+		  }
+		}
+		/* 5: center part */
+		if (width > 0 && height > 0) {
+		  unsigned int walky;
+		  for (walky = top_low_row;
+			walky < (unsigned int) unscaled_y_bottom;
+			++walky)
+		    {
+		    unsigned int walkx;
+		    base = spu->stride * walky;
+		    for (walkx = left_right_column;
+			    walkx < (unsigned int) unscaled_x_right;
+			    ++walkx) {
+		      tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]);
+		      alpha += tmp;
+		      color += tmp * spu->image[base + walkx];
+		    }
+		  }
+		}
+		/* 6: center right part */
+		if (right > 0.0 && height > 0) {
+		  unsigned int walky;
+		  for (walky = top_low_row;
+			walky < (unsigned int) unscaled_y_bottom;
+			++walky)
+		    {
+		    base = spu->stride * walky +
+			    (unsigned int) unscaled_x_right;
+		    tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]);
+		    alpha += tmp;
+		    color += tmp * spu->image[base];
+		  }
+		}
+		/* 7: bottom left part */
+		if (bottom > 0.0) {
+		  base = spu->stride * (unsigned int) unscaled_y_bottom +
+			    (unsigned int) unscaled_x;
+		  tmp = left * bottom * canon_alpha(spu->aimage[base]);
+		  alpha += tmp;
+		  color += tmp * spu->image[base];
+		}
+		/* 8: bottom center part */
+		if (width > 0 && bottom > 0.0) {
+		  unsigned int walkx;
+		  base = spu->stride * (unsigned int) unscaled_y_bottom;
+		  for (walkx = left_right_column;
+			walkx < (unsigned int) unscaled_x_right;
+			++walkx)
+		    {
+		    tmp = /* 1.0 * */ bottom *
+			canon_alpha(spu->aimage[base + walkx]);
+		    alpha += tmp;
+		    color += tmp * spu->image[base + walkx];
+		  }
+		}
+		/* 9: bottom right part */
+		if (right > 0.0 && bottom > 0.0) {
+		  base = spu->stride * (unsigned int)
+			unscaled_y_bottom + (unsigned int) unscaled_x_right;
+		  tmp = right * bottom * canon_alpha(spu->aimage[base]);
+		  alpha += tmp;
+		  color += tmp * spu->image[base];
+		}
+		/* Finally mix these transparency and brightness information suitably */
+		base = spu->scaled_stride * y + x;
+		spu->scaled_image[base] = alpha > 0 ? color / alpha : 0;
+		spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000;
+		if (spu->scaled_aimage[base]) {
+		  spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
+		  if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
+		    spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
+		}
+	      }
+	    }
+	    for (y = 0; y < spu->scaled_heightuv; ++y) {
+	      const double unscaled_y = y * inv_scaley;
+	      const double unscaled_y_bottom = unscaled_y + inv_scaley;
+	      const unsigned int top_low_row =
+			FFMIN(unscaled_y_bottom, unscaled_y + 1.0);
+	      const double top = top_low_row - unscaled_y;
+	      const unsigned int height = unscaled_y_bottom > top_low_row
+		? (unsigned int) unscaled_y_bottom - top_low_row
+		: 0;
+	      const double bottom = unscaled_y_bottom > top_low_row
+		? unscaled_y_bottom - floor(unscaled_y_bottom)
+		: 0.0;
+	      for (x = 0; x < spu->scaled_widthuv; ++x) {
+		const double unscaled_x = x * inv_scalex;
+		const double unscaled_x_right = unscaled_x + inv_scalex;
+		const unsigned int left_right_column =
+			FFMIN(unscaled_x_right, unscaled_x + 1.0);
+		const double left = left_right_column - unscaled_x;
+		const unsigned int width = unscaled_x_right > left_right_column
+		  ? (unsigned int) unscaled_x_right - left_right_column
+		  : 0;
+		const double right = unscaled_x_right > left_right_column
+		  ? unscaled_x_right - floor(unscaled_x_right)
+		  : 0.0;
+		double coloru = 0.0;
+		double colorv = 0.0;
+		double alpha = 0.0;
+		double tmp;
+		unsigned int base;
+		/* Now use these informations to compute a good alpha,
+                   and lightness.  The sum is on each of the 9
+                   region's surface and alpha and lightness.
+
+		  transformed alpha = sum(surface * alpha) / sum(surface)
+		  transformed color = sum(surface * alpha * color) / sum(surface * alpha)
+		*/
+		/* 1: top left part */
+		base = spu->strideuv * (unsigned int) unscaled_y;
+		tmp = left * top *
+		    canon_alpha(spu->aimageuv[base + (unsigned int) unscaled_x]);
+		alpha += tmp;
+		coloru += tmp * spu->imageu[base + (unsigned int) unscaled_x];
+		colorv += tmp * spu->imagev[base + (unsigned int) unscaled_x];
+		/* 2: top center part */
+		if (width > 0) {
+		  unsigned int walkx;
+		  for (walkx = left_right_column;
+			    walkx < (unsigned int) unscaled_x_right;
+			    ++walkx)
+		    {
+		    base = spu->strideuv * (unsigned int) unscaled_y + walkx;
+		    tmp = /* 1.0 * */ top * canon_alpha(spu->aimageuv[base]);
+		    alpha += tmp;
+		    coloru += tmp * spu->imageu[base];
+		    colorv += tmp * spu->imagev[base];
+		  }
+		}
+		/* 3: top right part */
+		if (right > 0.0) {
+		  base = spu->strideuv * (unsigned int) unscaled_y +
+			(unsigned int) unscaled_x_right;
+		  tmp = right * top * canon_alpha(spu->aimageuv[base]);
+		  alpha += tmp;
+		  coloru += tmp * spu->imageu[base];
+		  colorv += tmp * spu->imagev[base];
+		}
+		/* 4: center left part */
+		if (height > 0) {
+		  unsigned int walky;
+		  for (walky = top_low_row;
+			walky < (unsigned int) unscaled_y_bottom;
+			++walky)
+		    {
+		    base = spu->strideuv * walky + (unsigned int) unscaled_x;
+		    tmp = left /* * 1.0 */ * canon_alpha(spu->aimageuv[base]);
+		    alpha += tmp;
+		    coloru += tmp * spu->imageu[base];
+		    colorv += tmp * spu->imagev[base];
+		  }
+		}
+		/* 5: center part */
+		if (width > 0 && height > 0) {
+		  unsigned int walky;
+		  for (walky = top_low_row;
+			walky < (unsigned int) unscaled_y_bottom;
+			++walky)
+		    {
+		    unsigned int walkx;
+		    base = spu->strideuv * walky;
+		    for (walkx = left_right_column;
+			walkx < (unsigned int) unscaled_x_right;
+			++walkx)
+		    {
+		      tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimageuv[base + walkx]);
+		      alpha += tmp;
+		      coloru += tmp * spu->imageu[base + walkx];
+		      colorv += tmp * spu->imagev[base + walkx];
+		    }
+		  }
+		}
+		/* 6: center right part */
+		if (right > 0.0 && height > 0) {
+		  unsigned int walky;
+		  for (walky = top_low_row;
+			walky < (unsigned int) unscaled_y_bottom;
+			++walky)
+		    {
+		    base = spu->strideuv * walky +
+			    (unsigned int) unscaled_x_right;
+		    tmp = right /* * 1.0 */ * canon_alpha(spu->aimageuv[base]);
+		    alpha += tmp;
+		    coloru += tmp * spu->imageu[base];
+		    colorv += tmp * spu->imagev[base];
+		  }
+		}
+		/* 7: bottom left part */
+		if (bottom > 0.0) {
+		  base = spu->strideuv * (unsigned int) unscaled_y_bottom +
+			    (unsigned int) unscaled_x;
+		  tmp = left * bottom * canon_alpha(spu->aimageuv[base]);
+		  alpha += tmp;
+		  coloru += tmp * spu->imageu[base];
+		  colorv += tmp * spu->imagev[base];
+		}
+		/* 8: bottom center part */
+		if (width > 0 && bottom > 0.0) {
+		  unsigned int walkx;
+		  base = spu->strideuv * (unsigned int) unscaled_y_bottom;
+		  for (walkx = left_right_column;
+			    walkx < (unsigned int) unscaled_x_right;
+			    ++walkx) {
+		    tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimageuv[base + walkx]);
+		    alpha += tmp;
+		    coloru += tmp * spu->imageu[base + walkx];
+		    colorv += tmp * spu->imagev[base + walkx];
+		  }
+		}
+		/* 9: bottom right part */
+		if (right > 0.0 && bottom > 0.0) {
+		  base = spu->strideuv * (unsigned int) unscaled_y_bottom +
+			(unsigned int) unscaled_x_right;
+		  tmp = right * bottom * canon_alpha(spu->aimageuv[base]);
+		  alpha += tmp;
+		  coloru += tmp * spu->imageu[base];
+		  colorv += tmp * spu->imagev[base];
+		}
+		/* Finally mix these transparency and brightness information suitably */
+		base = spu->scaled_strideuv * y + x;
+		spu->scaled_imageu[base] = alpha > 0 ? coloru / alpha : 0;
+		spu->scaled_imagev[base] = alpha > 0 ? colorv / alpha : 0;
+		spu->scaled_aimageuv[base] = alpha * scalex * scaley / 0x10000;
+		if (spu->scaled_aimageuv[base]) {
+		  spu->scaled_aimageuv[base] = 256 - spu->scaled_aimageuv[base];
+		  if (spu->scaled_aimageuv[base] + spu->scaled_imageu[base] > 255)
+		    spu->scaled_imageu[base] = 256 - spu->scaled_aimageuv[base];
+		  if (spu->scaled_aimageuv[base] + spu->scaled_imagev[base] > 255)
+		    spu->scaled_imagev[base] = 256 - spu->scaled_aimageuv[base];
+		}
+	      }
+	    }
+	  }
+	  }
+nothing_to_do:
+	  /* Kludge: draw_alpha needs width multiple of 8. */
+	  if (spu->scaled_width < spu->scaled_stride)
+	    for (y = 0; y < spu->scaled_height; ++y) {
+	      memset(spu->scaled_aimage + y * spu->scaled_stride +
+		    spu->scaled_width, 0,
+		    spu->scaled_stride - spu->scaled_width);
+	    }
+	  spu->scaled_frame_width = dxs;
+	  spu->scaled_frame_height = dys;
+	  if (spu->scaled_widthuv < spu->scaled_strideuv)
+	    for (y = 0; y < spu->scaled_heightuv; ++y) {
+	      memset(spu->scaled_aimageuv + y * spu->scaled_stride +
+		    spu->scaled_widthuv, 0,
+		    spu->scaled_strideuv - spu->scaled_widthuv);
+	    }
+	  spu->scaled_frame_widthuv = dxs/2;
+	  spu->scaled_frame_heightuv = dys/2;
+	}
+      }
+      if (spu->scaled_image){
+        switch (spu_alignment) {
+        case 0:
+          spu->scaled_start_row = dys*sub_pos/100;
+	  if (spu->scaled_start_row + spu->scaled_height > dys)
+	    spu->scaled_start_row = dys - spu->scaled_height;
+          spu->scaled_start_rowuv = (dys/2)*sub_pos/100;
+	  if (spu->scaled_start_rowuv + spu->scaled_heightuv > (dys/2))
+	    spu->scaled_start_rowuv = (dys/2) - spu->scaled_heightuv;
+	  break;
+	case 1:
+          spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2;
+          if (sub_pos < 50) {
+	    if (spu->scaled_start_row < 0) spu->scaled_start_row = 0;
+	  } else {
+	    if (spu->scaled_start_row + spu->scaled_height > dys)
+	      spu->scaled_start_row = dys - spu->scaled_height;
+	  }
+          spu->scaled_start_rowuv = (dys/2)*sub_pos/100 - spu->scaled_heightuv/2;
+          if (sub_pos < 50) {
+	    if (spu->scaled_start_rowuv < 0) spu->scaled_start_rowuv = 0;
+	  } else {
+	    if (spu->scaled_start_rowuv + spu->scaled_heightuv > (dys/2))
+	      spu->scaled_start_rowuv = (dys/2) - spu->scaled_heightuv;
+	  }
+	  break;
+        case 2:
+          spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height;
+	  if (spu->scaled_start_row < 0) spu->scaled_start_row = 0;
+          spu->scaled_start_rowuv = (dys/2)*sub_pos/100 - spu->scaled_heightuv;
+	  if (spu->scaled_start_rowuv < 0) spu->scaled_start_rowuv = 0;
+	  break;
+	}
+	if (spu->dvdnav_color_spu==DVDNAV_SPU_YUY) {
+// Convert yuv to yuy
+	  if (!spu->imageyuy) spudec_create_yuy(spu,1);
+// Draw yuy
+	  if (spu->imageyuy) draw_alpha(spu->scaled_start_col,
+		    spu->scaled_start_row,
+		    spu->scaled_width*2,
+		    spu->scaled_height,
+		    DEST_PLANES_YUYV,
+		    spu->imageyuy,
+		    spu->aimageyuy,
+		    spu->strideyuy);
+	  } else {
+// Draw yuv Y, u and v planes
+	  draw_alpha(spu->scaled_start_col,
+		    spu->scaled_start_row,
+		    spu->scaled_width,
+		    spu->scaled_height,
+		    DEST_PLANES_Y,
+		    spu->scaled_image,
+		    spu->scaled_aimage,
+		    spu->scaled_stride);
+	  draw_alpha(spu->scaled_start_coluv,
+		    spu->scaled_start_rowuv,
+		    spu->scaled_widthuv,
+		    spu->scaled_heightuv,
+		    DEST_PLANES_U,
+		    spu->scaled_imageu,
+		    spu->scaled_aimageuv,
+		    spu->scaled_strideuv);
+	  draw_alpha(spu->scaled_start_coluv,
+		    spu->scaled_start_rowuv,
+		    spu->scaled_widthuv,
+		    spu->scaled_heightuv,
+		    DEST_PLANES_V,
+		    spu->scaled_imagev,
+		    spu->scaled_aimageuv,
+		    spu->scaled_strideuv);
+	  }
+	spu->spu_changed = 0;
+      }
+    }
+  }
+  else
+  {
+    mp_msg(MSGT_SPUDEC,MSGL_DBG2,
+	"SPU not displayed: start_pts=%d  end_pts=%d  now_pts=%d\n",
+        spu->start_pts, spu->end_pts, spu->now_pts);
+  }
+}
+
+//
+// Draw scaled image in RGB and BGR mode
+//	Note: expanded spudec_draw_scale with Green and Blue planes (Y->Red planes)
+//
+void spudec_draw_scaled_rgb(void *me, unsigned int dxs, unsigned int dys,
+	void (*draw_alpha)(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride))
+{
+  spudec_handle_t *spu = (spudec_handle_t *)me;
+  scale_pixel *table_x;
+  scale_pixel *table_y;
+  unsigned int scalex = 0;
+  unsigned int scaley = 0;
+
+  if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts) {
+
+    // check if only forced subtitles are requested
+    if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){
+	return;
+    }
+
+    if (!(spu_aamode&16) && (spu->orig_frame_width == 0 ||
+	spu->orig_frame_height == 0 ||
+	(spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
+      if (spu->image)
+      {
+      draw_alpha(spu->start_col,
+		spu->start_row,
+		spu->width,
+		spu->height,
+		DEST_PLANES_RB,
+		spu->image,
+		spu->aimage,
+		spu->stride);
+      draw_alpha(spu->start_col,
+		spu->start_row,
+		spu->width,
+		spu->height,
+		DEST_PLANES_G,
+		spu->imageu,
+		spu->aimage,
+		spu->stride);
+      draw_alpha(spu->start_col,
+		spu->start_row,
+		spu->width,
+		spu->height,
+		DEST_PLANES_BR,
+		spu->imagev,
+		spu->aimage,
+		spu->stride);
+      spu->spu_changed = 0;
+      }
+    }
+    else {
+      if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) {	/* Resizing is needed */
+	/* scaled_x = scalex * x / 0x100
+	   scaled_y = scaley * y / 0x100
+	   order of operations is important because of rounding. */
+	scalex = 0x100 * dxs / spu->orig_frame_width;
+	scaley = 0x100 * dys / spu->orig_frame_height;
+
+	spu->scaled_start_col = spu->start_col * scalex / 0x100;
+	spu->scaled_start_row = spu->start_row * scaley / 0x100;
+	spu->scaled_width = spu->width * scalex / 0x100;
+	spu->scaled_height = spu->height * scaley / 0x100;
+	/* Kludge: draw_alpha needs width multiple of 8 */
+	spu->scaled_stride = (spu->scaled_width + 7) & ~7;
+	if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) {
+	  if (spu->scaled_image) {
+	    free(spu->scaled_image);
+	  if (spu->scaled_imageu)
+	    free(spu->scaled_imageu);
+	    spu->scaled_image_size = 0;
+	  }
+	  spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height);
+	  spu->scaled_imageu = malloc(3 * spu->scaled_stride * spu->scaled_height);
+	  if (spu->scaled_image) {
+	    spu->scaled_image_size = spu->scaled_stride * spu->scaled_height;
+	    spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size;
+	  }
+	  if (spu->scaled_imageu) {
+	    spu->scaled_imagev = spu->scaled_imageu + spu->scaled_image_size;
+	  }
+	}
+	if (spu->scaled_image) {
+	  unsigned int x, y;
+	  if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
+	    goto nothing_to_do;
+	  }
+	  switch(spu_aamode&15) {
+	  case 4:
+	  sws_spu_image_rgb(spu->scaled_image,spu->scaled_imageu,
+		    spu->scaled_imagev, spu->scaled_aimage,
+		    spu->scaled_width, spu->scaled_height, spu->scaled_stride,
+		    spu->image, spu->imageu, spu->imagev, spu->aimage,
+		    spu->width, spu->height, spu->stride);
+	  break;
+	  case 3:
+	  table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
+	  table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
+	  if (!table_x || !table_y) {
+	    mp_msg(MSGT_SPUDEC, MSGL_FATAL,
+		    "Fatal: spudec_draw_scaled: calloc failed\n");
+	  }
+	  scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x);
+	  scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y);
+	  for (y = 0; y < spu->scaled_height; y++)
+	    for (x = 0; x < spu->scaled_width; x++)
+	      scale_image_rgb(x, y, table_x, table_y, spu);
+	  free(table_x);
+	  free(table_y);
+	  break;
+	  case 0:
+	  /* no antialiasing */
+	  for (y = 0; y < spu->scaled_height; ++y) {
+	    int unscaled_y = y * 0x100 / scaley;
+	    int strides = spu->stride * unscaled_y;
+	    int scaled_strides = spu->scaled_stride * y;
+	    for (x = 0; x < spu->scaled_width; ++x) {
+	      int unscaled_x = x * 0x100 / scalex;
+	      spu->scaled_image[scaled_strides + x] =
+		    spu->image[strides + unscaled_x];
+	      spu->scaled_imageu[scaled_strides + x] =
+		    spu->imageu[strides + unscaled_x];
+	      spu->scaled_imagev[scaled_strides + x] =
+		    spu->imagev[strides + unscaled_x];
+	      spu->scaled_aimage[scaled_strides + x] =
+		    spu->aimage[strides + unscaled_x];
+	    }
+	  }
+	  break;
+	  case 1:
+	  {
+	    /* Intermediate antialiasing. */
+	    for (y = 0; y < spu->scaled_height; ++y) {
+	      const unsigned int unscaled_top = y *
+			spu->orig_frame_height / dys;
+	      unsigned int unscaled_bottom = (y + 1) *
+			spu->orig_frame_height / dys;
+	      if (unscaled_bottom >= spu->height)
+		unscaled_bottom = spu->height - 1;
+	      for (x = 0; x < spu->scaled_width; ++x) {
+		const unsigned int unscaled_left = x *
+			    spu->orig_frame_width / dxs;
+		unsigned int unscaled_right = (x + 1) *
+			    spu->orig_frame_width / dxs;
+		unsigned int colorr = 0;
+		unsigned int colorg = 0;
+		unsigned int colorb = 0;
+		unsigned int alpha = 0;
+		unsigned int walkx, walky;
+		unsigned int base, tmp;
+		if (unscaled_right >= spu->width)
+		  unscaled_right = spu->width - 1;
+		for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
+		  for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) {
+		    base = walky * spu->stride + walkx;
+		    tmp = canon_alpha(spu->aimage[base]);
+		    alpha += tmp;
+		    colorr += tmp * spu->image[base];
+		    colorg += tmp * spu->imageu[base];
+		    colorb += tmp * spu->imagev[base];
+		  }
+		base = y * spu->scaled_stride + x;
+		spu->scaled_image[base] = alpha ? colorr / alpha : 0;
+		spu->scaled_imageu[base] = alpha ? colorg / alpha : 0;
+		spu->scaled_imagev[base] = alpha ? colorb / alpha : 0;
+		spu->scaled_aimage[base] =
+		  alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left);
+		/* spu->scaled_aimage[base] =
+		  alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
+		if (spu->scaled_aimage[base]) {
+		  spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
+		  if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
+		    spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
+		  if (spu->scaled_aimage[base] + spu->scaled_imageu[base] > 255)
+		    spu->scaled_imageu[base] = 256 - spu->scaled_aimage[base];
+		  if (spu->scaled_aimage[base] + spu->scaled_imagev[base] > 255)
+		    spu->scaled_imagev[base] = 256 - spu->scaled_aimage[base];
+		}
+	      }
+	    }
+	  }
+	  break;
+	  case 2:
+	  {
+	    /* Best antialiasing.  Very slow. */
+	    /* Any pixel (x, y) represents pixels from the original
+	       rectangular region comprised between the columns
+	       unscaled_y and unscaled_y + 0x100 / scaley and the rows
+	       unscaled_x and unscaled_x + 0x100 / scalex
+
+	       The original rectangular region that the scaled pixel
+	       represents is cut in 9 rectangular areas like this:
+
+	       +---+-----------------+---+
+	       | 1 |        2        | 3 |
+	       +---+-----------------+---+
+	       |   |                 |   |
+	       | 4 |        5        | 6 |
+	       |   |                 |   |
+	       +---+-----------------+---+
+	       | 7 |        8        | 9 |
+	       +---+-----------------+---+
+
+	       The width of the left column is at most one pixel and
+	       it is never null and its right column is at a pixel
+	       boundary.  The height of the top row is at most one
+	       pixel it is never null and its bottom row is at a
+	       pixel boundary. The width and height of region 5 are
+	       integral values.  The width of the right column is
+	       what remains and is less than one pixel.  The height
+	       of the bottom row is what remains and is less than
+	       one pixel.
+
+	       The row above 1, 2, 3 is unscaled_y.  The row between
+	       1, 2, 3 and 4, 5, 6 is top_low_row.  The row between 4,
+	       5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
+	       The row beneath 7, 8, 9 is unscaled_y_bottom.
+
+	       The column left of 1, 4, 7 is unscaled_x.  The column
+	       between 1, 4, 7 and 2, 5, 8 is left_right_column.  The
+	       column between 2, 5, 8 and 3, 6, 9 is (unsigned
+	       int)unscaled_x_right.  The column right of 3, 6, 9 is
+	       unscaled_x_right. */
+	    const double inv_scalex = (double) 0x100 / scalex;
+	    const double inv_scaley = (double) 0x100 / scaley;
+	    for (y = 0; y < spu->scaled_height; ++y) {
+	      const double unscaled_y = y * inv_scaley;
+	      const double unscaled_y_bottom = unscaled_y + inv_scaley;
+	      const unsigned int top_low_row =
+			FFMIN(unscaled_y_bottom, unscaled_y + 1.0);
+	      const double top = top_low_row - unscaled_y;
+	      const unsigned int height = unscaled_y_bottom > top_low_row
+		? (unsigned int) unscaled_y_bottom - top_low_row
+		: 0;
+	      const double bottom = unscaled_y_bottom > top_low_row
+		? unscaled_y_bottom - floor(unscaled_y_bottom)
+		: 0.0;
+	      for (x = 0; x < spu->scaled_width; ++x) {
+		const double unscaled_x = x * inv_scalex;
+		const double unscaled_x_right = unscaled_x + inv_scalex;
+		const unsigned int left_right_column =
+			FFMIN(unscaled_x_right, unscaled_x + 1.0);
+		const double left = left_right_column - unscaled_x;
+		const unsigned int width = unscaled_x_right > left_right_column
+		  ? (unsigned int) unscaled_x_right - left_right_column
+		  : 0;
+		const double right = unscaled_x_right > left_right_column
+		  ? unscaled_x_right - floor(unscaled_x_right)
+		  : 0.0;
+		double colorr = 0.0;
+		double colorg = 0.0;
+		double colorb = 0.0;
+		double alpha = 0.0;
+		double tmp;
+		unsigned int base;
+		/* Now use these informations to compute a good alpha,
+                   and lightness.  The sum is on each of the 9
+                   region's surface and alpha and lightness.
+
+		  transformed alpha = sum(surface * alpha) / sum(surface)
+		  transformed color = sum(surface * alpha * color) / sum(surface * alpha)
+		*/
+		/* 1: top left part */
+		base = spu->stride * (unsigned int) unscaled_y;
+		tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
+		alpha += tmp;
+		colorr += tmp * spu->image[base + (unsigned int) unscaled_x];
+		colorg += tmp * spu->imageu[base + (unsigned int) unscaled_x];
+		colorb += tmp * spu->imagev[base + (unsigned int) unscaled_x];
+		/* 2: top center part */
+		if (width > 0) {
+		  unsigned int walkx;
+		  for (walkx = left_right_column;
+			    walkx < (unsigned int) unscaled_x_right;
+			    ++walkx) {
+		    base = spu->stride * (unsigned int) unscaled_y + walkx;
+		    tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]);
+		    alpha += tmp;
+		    colorr += tmp * spu->image[base];
+		    colorg += tmp * spu->imageu[base];
+		    colorb += tmp * spu->imagev[base];
+		  }
+		}
+		/* 3: top right part */
+		if (right > 0.0) {
+		  base = spu->stride * (unsigned int) unscaled_y +
+			    (unsigned int) unscaled_x_right;
+		  tmp = right * top * canon_alpha(spu->aimage[base]);
+		  alpha += tmp;
+		  colorr += tmp * spu->image[base];
+		  colorg += tmp * spu->imageu[base];
+		  colorb += tmp * spu->imagev[base];
+		}
+		/* 4: center left part */
+		if (height > 0) {
+		  unsigned int walky;
+		  for (walky = top_low_row;
+			    walky < (unsigned int) unscaled_y_bottom;
+			    ++walky) {
+		    base = spu->stride * walky + (unsigned int) unscaled_x;
+		    tmp = left /* * 1.0 */ * canon_alpha(spu->aimage[base]);
+		    alpha += tmp;
+		    colorr += tmp * spu->image[base];
+		    colorg += tmp * spu->imageu[base];
+		    colorb += tmp * spu->imagev[base];
+		  }
+		}
+		/* 5: center part */
+		if (width > 0 && height > 0) {
+		  unsigned int walky;
+		  for (walky = top_low_row;
+			    walky < (unsigned int) unscaled_y_bottom;
+			    ++walky) {
+		    unsigned int walkx;
+		    base = spu->stride * walky;
+		    for (walkx = left_right_column;
+			    walkx < (unsigned int) unscaled_x_right;
+			    ++walkx) {
+		      tmp = /* 1.0 * 1.0 * */ canon_alpha(spu->aimage[base + walkx]);
+		      alpha += tmp;
+		      colorr += tmp * spu->image[base + walkx];
+		      colorg += tmp * spu->imageu[base + walkx];
+		      colorb += tmp * spu->imagev[base + walkx];
+		    }
+		  }
+		}
+		/* 6: center right part */
+		if (right > 0.0 && height > 0) {
+		  unsigned int walky;
+		  for (walky = top_low_row;
+				walky < (unsigned int) unscaled_y_bottom;
+				++walky) {
+		    base = spu->stride * walky + (unsigned int) unscaled_x_right;
+		    tmp = right /* * 1.0 */ * canon_alpha(spu->aimage[base]);
+		    alpha += tmp;
+		    colorr += tmp * spu->image[base];
+		    colorg += tmp * spu->imageu[base];
+		    colorb += tmp * spu->imagev[base];
+		  }
+		}
+		/* 7: bottom left part */
+		if (bottom > 0.0) {
+		  base = spu->stride * (unsigned int) unscaled_y_bottom +
+			    (unsigned int) unscaled_x;
+		  tmp = left * bottom * canon_alpha(spu->aimage[base]);
+		  alpha += tmp;
+		  colorr += tmp * spu->image[base];
+		  colorg += tmp * spu->imageu[base];
+		  colorb += tmp * spu->imagev[base];
+		}
+		/* 8: bottom center part */
+		if (width > 0 && bottom > 0.0) {
+		  unsigned int walkx;
+		  base = spu->stride * (unsigned int) unscaled_y_bottom;
+		  for (walkx = left_right_column;
+			    walkx < (unsigned int) unscaled_x_right;
+			    ++walkx) {
+		    tmp = /* 1.0 * */ bottom * canon_alpha(spu->aimage[base + walkx]);
+		    alpha += tmp;
+		    colorr += tmp * spu->image[base + walkx];
+		    colorg += tmp * spu->imageu[base + walkx];
+		    colorb += tmp * spu->imagev[base + walkx];
+		  }
+		}
+		/* 9: bottom right part */
+		if (right > 0.0 && bottom > 0.0) {
+		  base = spu->stride * (unsigned int) unscaled_y_bottom +
+			    (unsigned int) unscaled_x_right;
+		  tmp = right * bottom * canon_alpha(spu->aimage[base]);
+		  alpha += tmp;
+		  colorr += tmp * spu->image[base];
+		  colorg += tmp * spu->imageu[base];
+		  colorb += tmp * spu->imagev[base];
+		}
+		/* Finally mix these transparency and brightness information suitably */
+		base = spu->scaled_stride * y + x;
+		spu->scaled_image[base] = alpha > 0 ? colorr / alpha : 0;
+		spu->scaled_imageu[base] = alpha > 0 ? colorg / alpha : 0;
+		spu->scaled_imagev[base] = alpha > 0 ? colorb / alpha : 0;
+		spu->scaled_aimage[base] = alpha * scalex * scaley / 0x10000;
+		if (spu->scaled_aimage[base]) {
+		  spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
+		  if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
+		    spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
+		  if (spu->scaled_aimage[base] + spu->scaled_imageu[base] > 255)
+		    spu->scaled_imageu[base] = 256 - spu->scaled_aimage[base];
+		  if (spu->scaled_aimage[base] + spu->scaled_imagev[base] > 255)
+		    spu->scaled_imagev[base] = 256 - spu->scaled_aimage[base];
+		}
+	      }
+	    }
+	  }
+	  }
+nothing_to_do:
+	  /* Kludge: draw_alpha needs width multiple of 8. */
+	  if (spu->scaled_width < spu->scaled_stride)
+	    for (y = 0; y < spu->scaled_height; ++y) {
+	      memset(spu->scaled_aimage + y * spu->scaled_stride +
+			spu->scaled_width, 0,
+			spu->scaled_stride - spu->scaled_width);
+	    }
+	  spu->scaled_frame_width = dxs;
+	  spu->scaled_frame_height = dys;
+	}
+      }
+      if (spu->scaled_image){
+        switch (spu_alignment) {
+        case 0:
+          spu->scaled_start_row = dys*sub_pos/100;
+	  if (spu->scaled_start_row + spu->scaled_height > dys)
+	    spu->scaled_start_row = dys - spu->scaled_height;
+	  break;
+	case 1:
+          spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height/2;
+          if (sub_pos < 50) {
+	    if (spu->scaled_start_row < 0) spu->scaled_start_row = 0;
+	  } else {
+	    if (spu->scaled_start_row + spu->scaled_height > dys)
+	      spu->scaled_start_row = dys - spu->scaled_height;
+	  }
+	  break;
+        case 2:
+          spu->scaled_start_row = dys*sub_pos/100 - spu->scaled_height;
+	  if (spu->scaled_start_row < 0) spu->scaled_start_row = 0;
+	  break;
+	}
+// Draw planes: Red in RGB mode or Blue in BGR mode
+	draw_alpha(spu->scaled_start_col,
+		spu->scaled_start_row,
+		spu->scaled_width,
+		spu->scaled_height,
+		DEST_PLANES_RB,
+		spu->scaled_image,
+		spu->scaled_aimage,
+		spu->scaled_stride);
+// Draw Green planes in RGB and BGR mode
+	draw_alpha(spu->scaled_start_col,
+		spu->scaled_start_row,
+		spu->scaled_width,
+		spu->scaled_height,
+		DEST_PLANES_G,
+		spu->scaled_imageu,
+		spu->scaled_aimage,
+		spu->scaled_stride);
+// Draw planes: Blue in RGB mode or Red in BGR mode
+	draw_alpha(spu->scaled_start_col,
+		spu->scaled_start_row,
+		spu->scaled_width,
+		spu->scaled_height,
+		DEST_PLANES_BR,
+		spu->scaled_imagev,
+		spu->scaled_aimage,
+		spu->scaled_stride);
+	spu->spu_changed = 0;
+      }
+    }
+  }
+  else
+  {
+    mp_msg(MSGT_SPUDEC,MSGL_DBG2,
+	"SPU not displayed: start_pts=%d  end_pts=%d  now_pts=%d\n",
+        spu->start_pts, spu->end_pts, spu->now_pts);
+  }
+}
+
+void spudec_draw_scaled(void *me, unsigned int dxs, unsigned int dys, void (*draw_alpha)(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride))
+{
+  spudec_handle_t *spu = (spudec_handle_t *)me;
+  scale_pixel *table_x;
+  scale_pixel *table_y;
+  if (spu->dvdnav_menu) {
+    switch (spu->dvdnav_color_spu)
+      {
+//
+// Draw scaled image in YUV and YUY mode
+//
+      case DVDNAV_SPU_YUV:
+      case DVDNAV_SPU_YUY:
+        spudec_draw_scaled_yuv(me,dxs,dys,draw_alpha);
+	return;
+	break;
+//
+// Draw scaled image in RGB and BGR mode
+//
+      case DVDNAV_SPU_RGB:
+      case DVDNAV_SPU_BGR:
+        spudec_draw_scaled_rgb(me,dxs,dys,draw_alpha);
+	return;
+	break;
+      }
+    }
+//
+// Draw scaled image in Y mode (default)
+//
+  if (spu->start_pts <= spu->now_pts && spu->now_pts < spu->end_pts) {
+
+    // check if only forced subtitles are requested 
+    if( (spu->forced_subs_only) && !(spu->is_forced_sub) ){ 
+	return;
+    }
+
+    if (!(spu_aamode&16) && (spu->orig_frame_width == 0 || spu->orig_frame_height == 0
+	|| (spu->orig_frame_width == dxs && spu->orig_frame_height == dys))) {
+      if (spu->image)
+      {
+	draw_alpha(spu->start_col, spu->start_row, spu->width, spu->height,DEST_PLANES_Y,
+		   spu->image, spu->aimage, spu->stride);
+	spu->spu_changed = 0;
+      }
+    }
+    else {
+      if (spu->scaled_frame_width != dxs || spu->scaled_frame_height != dys) {	/* Resizing is needed */
+	/* scaled_x = scalex * x / 0x100
+	   scaled_y = scaley * y / 0x100
+	   order of operations is important because of rounding. */
+	unsigned int scalex = 0x100 * dxs / spu->orig_frame_width;
+	unsigned int scaley = 0x100 * dys / spu->orig_frame_height;
+	spu->scaled_start_col = spu->start_col * scalex / 0x100;
+	spu->scaled_start_row = spu->start_row * scaley / 0x100;
+	spu->scaled_width = spu->width * scalex / 0x100;
+	spu->scaled_height = spu->height * scaley / 0x100;
+	/* Kludge: draw_alpha needs width multiple of 8 */
+	spu->scaled_stride = (spu->scaled_width + 7) & ~7;
+	if (spu->scaled_image_size < spu->scaled_stride * spu->scaled_height) {
+	  if (spu->scaled_image) {
+	    free(spu->scaled_image);
+	    spu->scaled_image_size = 0;
+	  }
+	  spu->scaled_image = malloc(2 * spu->scaled_stride * spu->scaled_height);
+	  if (spu->scaled_image) {
+	    spu->scaled_image_size = spu->scaled_stride * spu->scaled_height;
+	    spu->scaled_aimage = spu->scaled_image + spu->scaled_image_size;
+	  }
+	}
+	if (spu->scaled_image) {
+	  unsigned int x, y;
+	  if (spu->scaled_width <= 1 || spu->scaled_height <= 1) {
+	    goto nothing_to_do;
+	  }
+	  switch(spu_aamode&15) {
+	  case 4:
+	  sws_spu_image(spu->scaled_image, spu->scaled_aimage,
+		  spu->scaled_width, spu->scaled_height, spu->scaled_stride,
+		  spu->image, spu->aimage, spu->width, spu->height, spu->stride);
+	  break;
+	  case 3:
+	  table_x = calloc(spu->scaled_width, sizeof(scale_pixel));
+	  table_y = calloc(spu->scaled_height, sizeof(scale_pixel));
+	  if (!table_x || !table_y) {
+	    mp_msg(MSGT_SPUDEC, MSGL_FATAL, "Fatal: spudec_draw_scaled: calloc failed\n");
+	  }
+	  scale_table(0, 0, spu->width - 1, spu->scaled_width - 1, table_x);
+	  scale_table(0, 0, spu->height - 1, spu->scaled_height - 1, table_y);
+	  for (y = 0; y < spu->scaled_height; y++)
+	    for (x = 0; x < spu->scaled_width; x++)
+	      scale_image(x, y, table_x, table_y, spu);
+	  free(table_x);
+	  free(table_y);
+	  break;
+	  case 0:
+	  /* no antialiasing */
+	  for (y = 0; y < spu->scaled_height; ++y) {
+	    int unscaled_y = y * 0x100 / scaley;
+	    int strides = spu->stride * unscaled_y;
+	    int scaled_strides = spu->scaled_stride * y;
+	    for (x = 0; x < spu->scaled_width; ++x) {
+	      int unscaled_x = x * 0x100 / scalex;
+	      spu->scaled_image[scaled_strides + x] = spu->image[strides + unscaled_x];
+	      spu->scaled_aimage[scaled_strides + x] = spu->aimage[strides + unscaled_x];
+	    }
+	  }
+	  break;
+	  case 1:
+	  {
+	    /* Intermediate antialiasing. */
+	    for (y = 0; y < spu->scaled_height; ++y) {
+	      const unsigned int unscaled_top = y * spu->orig_frame_height / dys;
+	      unsigned int unscaled_bottom = (y + 1) * spu->orig_frame_height / dys;
+	      if (unscaled_bottom >= spu->height)
+		unscaled_bottom = spu->height - 1;
+	      for (x = 0; x < spu->scaled_width; ++x) {
+		const unsigned int unscaled_left = x * spu->orig_frame_width / dxs;
+		unsigned int unscaled_right = (x + 1) * spu->orig_frame_width / dxs;
+		unsigned int color = 0;
+		unsigned int alpha = 0;
+		unsigned int walkx, walky;
+		unsigned int base, tmp;
+		if (unscaled_right >= spu->width)
+		  unscaled_right = spu->width - 1;
+		for (walky = unscaled_top; walky <= unscaled_bottom; ++walky)
+		  for (walkx = unscaled_left; walkx <= unscaled_right; ++walkx) {
+		    base = walky * spu->stride + walkx;
+		    tmp = canon_alpha(spu->aimage[base]);
+		    alpha += tmp;
+		    color += tmp * spu->image[base];
+		  }
+		base = y * spu->scaled_stride + x;
+		spu->scaled_image[base] = alpha ? color / alpha : 0;
+		spu->scaled_aimage[base] =
+		  alpha * (1 + unscaled_bottom - unscaled_top) * (1 + unscaled_right - unscaled_left);
+		/* spu->scaled_aimage[base] =
+		  alpha * dxs * dys / spu->orig_frame_width / spu->orig_frame_height; */
+		if (spu->scaled_aimage[base]) {
+		  spu->scaled_aimage[base] = 256 - spu->scaled_aimage[base];
+		  if (spu->scaled_aimage[base] + spu->scaled_image[base] > 255)
+		    spu->scaled_image[base] = 256 - spu->scaled_aimage[base];
+		}
+	      }
+	    }
+	  }
+	  break;
+	  case 2:
+	  {
+	    /* Best antialiasing.  Very slow. */
+	    /* Any pixel (x, y) represents pixels from the original
+	       rectangular region comprised between the columns
+	       unscaled_y and unscaled_y + 0x100 / scaley and the rows
+	       unscaled_x and unscaled_x + 0x100 / scalex
+
+	       The original rectangular region that the scaled pixel
+	       represents is cut in 9 rectangular areas like this:
+	       
+	       +---+-----------------+---+
+	       | 1 |        2        | 3 |
+	       +---+-----------------+---+
+	       |   |                 |   |
+	       | 4 |        5        | 6 |
+	       |   |                 |   |
+	       +---+-----------------+---+
+	       | 7 |        8        | 9 |
+	       +---+-----------------+---+
+
+	       The width of the left column is at most one pixel and
+	       it is never null and its right column is at a pixel
+	       boundary.  The height of the top row is at most one
+	       pixel it is never null and its bottom row is at a
+	       pixel boundary. The width and height of region 5 are
+	       integral values.  The width of the right column is
+	       what remains and is less than one pixel.  The height
+	       of the bottom row is what remains and is less than
+	       one pixel.
+
+	       The row above 1, 2, 3 is unscaled_y.  The row between
+	       1, 2, 3 and 4, 5, 6 is top_low_row.  The row between 4,
+	       5, 6 and 7, 8, 9 is (unsigned int)unscaled_y_bottom.
+	       The row beneath 7, 8, 9 is unscaled_y_bottom.
+
+	       The column left of 1, 4, 7 is unscaled_x.  The column
+	       between 1, 4, 7 and 2, 5, 8 is left_right_column.  The
+	       column between 2, 5, 8 and 3, 6, 9 is (unsigned
+	       int)unscaled_x_right.  The column right of 3, 6, 9 is
+	       unscaled_x_right. */
+	    const double inv_scalex = (double) 0x100 / scalex;
+	    const double inv_scaley = (double) 0x100 / scaley;
+	    for (y = 0; y < spu->scaled_height; ++y) {
+	      const double unscaled_y = y * inv_scaley;
+	      const double unscaled_y_bottom = unscaled_y + inv_scaley;
+	      const unsigned int top_low_row = FFMIN(unscaled_y_bottom, unscaled_y + 1.0);
+	      const double top = top_low_row - unscaled_y;
+	      const unsigned int height = unscaled_y_bottom > top_low_row
+		? (unsigned int) unscaled_y_bottom - top_low_row
+		: 0;
+	      const double bottom = unscaled_y_bottom > top_low_row
+		? unscaled_y_bottom - floor(unscaled_y_bottom)
+		: 0.0;
+	      for (x = 0; x < spu->scaled_width; ++x) {
+		const double unscaled_x = x * inv_scalex;
+		const double unscaled_x_right = unscaled_x + inv_scalex;
+		const unsigned int left_right_column = FFMIN(unscaled_x_right, unscaled_x + 1.0);
+		const double left = left_right_column - unscaled_x;
+		const unsigned int width = unscaled_x_right > left_right_column
+		  ? (unsigned int) unscaled_x_right - left_right_column
+		  : 0;
+		const double right = unscaled_x_right > left_right_column
+		  ? unscaled_x_right - floor(unscaled_x_right)
+		  : 0.0;
+		double color = 0.0;
+		double alpha = 0.0;
+		double tmp;
+		unsigned int base;
+		/* Now use these informations to compute a good alpha,
+                   and lightness.  The sum is on each of the 9
+                   region's surface and alpha and lightness.
+
+		  transformed alpha = sum(surface * alpha) / sum(surface)
+		  transformed color = sum(surface * alpha * color) / sum(surface * alpha)
+		*/
+		/* 1: top left part */
+		base = spu->stride * (unsigned int) unscaled_y;
+		tmp = left * top * canon_alpha(spu->aimage[base + (unsigned int) unscaled_x]);
+		alpha += tmp;
+		color += tmp * spu->image[base + (unsigned int) unscaled_x];
+		/* 2: top center part */
+		if (width > 0) {
+		  unsigned int walkx;
+		  for (walkx = left_right_column; walkx < (unsigned int) unscaled_x_right; ++walkx) {
+		    base = spu->stride * (unsigned int) unscaled_y + walkx;
+		    tmp = /* 1.0 * */ top * canon_alpha(spu->aimage[base]);
+		    alpha += tmp;
+		    color += tmp * spu->image[base];
+		  }
+		}
+		/* 3: top right part */
+		if (right > 0.0) {
+		  base = spu->stride * (unsigned int) unscaled_y + (unsigned int) unscaled_x_right;
 		  tmp = right * top * canon_alpha(spu->aimage[base]);
 		  alpha += tmp;
 		  color += tmp * spu->image[base];
@@ -1082,7 +3171,7 @@
 	  break;
 	}
 	draw_alpha(spu->scaled_start_col, spu->scaled_start_row, spu->scaled_width, spu->scaled_height,
-		   spu->scaled_image, spu->scaled_aimage, spu->scaled_stride);
+		    DEST_PLANES_Y,spu->scaled_image, spu->scaled_aimage, spu->scaled_stride);
 	spu->spu_changed = 0;
       }
     }
@@ -1166,6 +3255,21 @@
 	free(spu->scaled_image);
     if (spu->image)
       free(spu->image);
+    if (spu->dvdnav_image)	// Free dvdnav SPU image
+      free(spu->dvdnav_image);
+    if (spu->dvdnav_aimage)	// Free dvdnav SPU image alpha
+      free(spu->dvdnav_aimage);
+
+    if (spu->imageu)		// Free dvdnav SPU uv or GB image
+      free(spu->imageu);
+    if (spu->imageyuy)		// Free dvdnav SPU YUY image
+      free(spu->imageyuy);
+    spu->imageyuy=NULL;
+    if (spu->scaled_imageu)	// Free dvdnav SPU uv or GB alpha
+	free(spu->scaled_imageu);
+
+    if (spu->last_packet) {spudec_free_packet(spu->last_packet); spu->last_packet=NULL;}
+    spu->dvdnav_allocated = 0;
     free(spu);
   }
 }
--- spudec.h	2007-10-07 21:49:33.000000000 +0200
+++ spudec.h	2007-10-08 21:10:30.000000000 +0200
@@ -5,8 +5,38 @@
 
 void spudec_heartbeat(void *this, unsigned int pts100);
 void spudec_assemble(void *this, unsigned char *packet, unsigned int len, unsigned int pts100);
-void spudec_draw(void *this, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride));
-void spudec_draw_scaled(void *this, unsigned int dxs, unsigned int dys, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride));
+void spudec_draw(void *this, void (*draw_alpha)(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride));
+void spudec_draw_scaled(void *this, unsigned int dxs, unsigned int dys, void (*draw_alpha)(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride));
+
+#define DVDNAV_SPU_YUV	1
+#define DVDNAV_SPU_RGB	2
+#define DVDNAV_SPU_BGR	3
+#define DVDNAV_SPU_YUY	4
+
+// Convert yuv color to rgb color
+void spu_yuv_to_rgb(unsigned int y,unsigned int u,unsigned int v,
+    unsigned int *r,unsigned int *g,unsigned int *b);
+// Enable/disable dvdmenu mode, and set color mode
+//	cflg = 0:	Y SPU (default)
+//	cflg = 1:	YUV SPU
+//	cflg = 2:	RGB SPU
+//	cflg = 3:	BGR SPU
+//	cflg = 4:	YUY SPU
+void spudec_dvdnav_mode(void *this, int mode, int cflg);
+// Set dvd menu button draw area and palette
+void spudec_dvdnav_area(void *this, uint16_t sx, uint16_t sy,
+    uint16_t ex, uint16_t ey, uint32_t palette);
+// Set dvd menu button palette
+void spudec_dvdnav_palette(void *this, uint32_t palette);
+// Draw scaled image in YUV and YUY mode
+void spudec_draw_scaled_yuv(void *me, unsigned int dxs, unsigned int dys,
+    void (*draw_alpha)(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride));
+// Draw scaled image in RGB and BGR mode
+void spudec_draw_scaled_rgb(void *me, unsigned int dxs, unsigned int dys,
+    void (*draw_alpha)(int x0,int y0, int w,int h, int dp, unsigned char* src, unsigned char *srca, int stride));
+// Convert Yuv image to YuY image
+void spudec_create_yuy(void *this, int spu_scaled);
+
 void spudec_update_palette(void *this, unsigned int *palette);
 void *spudec_new_scaled(unsigned int *palette, unsigned int frame_width, unsigned int frame_height);
 void *spudec_new_scaled_vobsub(unsigned int *palette, unsigned int *cuspal, unsigned int custom, unsigned int frame_width, unsigned int frame_height);
--- mp_core.h	2007-10-07 21:49:33.000000000 +0200
+++ mp_core.h	2007-10-08 20:48:06.000000000 +0200
@@ -99,6 +99,14 @@
 #endif
 
     int was_paused;
+#ifdef USE_DVDNAV
+    void *smpi;          // store last decoded video image
+    void *last_buffer;   // store last read video frame
+    void *last_start;    // video read buffer ptr
+    int last_in_size;    // last read size
+    int libmpeg2_count;  // libmpeg2 repeat decode counter
+    int dup_frame;       // duplicate frame mode
+#endif
 } MPContext;
 
 
--- stream/stream_dvdnav.c	2007-10-07 21:49:26.000000000 +0200
+++ stream/stream_dvdnav.c	2007-10-23 16:56:29.000000000 +0200
@@ -10,6 +10,7 @@
 #include "stream.h"
 #include "libmpdemux/demuxer.h"
 #include "stream_dvdnav.h"
+#include "stream_dvd_common.h"
 #include "libvo/video_out.h"
 #include "libavutil/common.h"
 #include "spudec.h"
@@ -18,16 +19,13 @@
 #include "help_mp.h"
 
 extern char *dvd_device;
-extern int dvd_chapter;
-extern int dvd_last_chapter;
-extern int dvd_angle;
 extern char *audio_lang, *dvdsub_lang;
 
 static struct stream_priv_s {
   int track;
   char* device;
 } stream_priv_dflts = {
-  0,
+  -1,
   NULL
 };
 
@@ -114,6 +112,8 @@
   dvdnav_get_current_highlight (priv->dvdnav, &(hlev->buttonN));
   hlev->display = display_mode; /* show */
 
+  if (hlev->buttonN > pnavpci->hli.hl_gi.btn_ns && pnavpci->hli.hl_gi.btn_ns > 0)
+    hlev->buttonN = pnavpci->hli.hl_gi.btn_ns;
   if (hlev->buttonN > 0 && pnavpci->hli.hl_gi.btn_ns > 0 && hlev->display) {
     for (btnum = 0; btnum < pnavpci->hli.hl_gi.btn_ns; btnum++) {
       btni_t *btni = &(pnavpci->hli.btnit[btnum]);
@@ -138,6 +138,8 @@
 
 static int dvdnav_stream_read(dvdnav_priv_t * priv, unsigned char *buf, int *len) {
   int event = DVDNAV_NOP;
+  uint32_t nextstill;
+  dvdnav_still_event_t *still_event;
 
   if (!len) return -1;
   *len=-1;
@@ -154,7 +156,18 @@
       case DVDNAV_NAV_PACKET:
         return event;
       case DVDNAV_STILL_FRAME: {
-        dvdnav_still_skip(priv->dvdnav); // don't let dvdnav stall on this image
+        still_event = (dvdnav_still_event_t*)(buf);
+        priv->still_length=still_event->length;
+        // set still frame duration
+        if (priv->still_length!=255)
+          priv->duration = priv->still_length * 1000;
+        else
+          priv->duration = 0;
+        // FIXME: TIME HACK
+        if (priv->still_length<=1) {
+          pci_t* pnavpci = dvdnav_get_current_nav_pci( priv->dvdnav );
+          priv->duration = mp_dvdtimetomsec(&(pnavpci->pci_gi.e_eltm));
+        }
         break;
       }
       case DVDNAV_HIGHLIGHT: {
@@ -162,20 +175,54 @@
         break;
       }
       case DVDNAV_CELL_CHANGE: {
+        priv->status &= ~NAV_FLAG_WAIT_SKIP;    // clear
+        priv->status |= NAV_FLAG_STREAM_CHANGE; // changed stream
+        priv->status |= NAV_FLAG_SPU_CHANGE;    // changed SPU
         dvdnav_cell_change_event_t *ev =  (dvdnav_cell_change_event_t*)buf;
         if(ev->pgc_length)
           priv->duration = ev->pgc_length/90;
+        if (dvdnav_is_domain_vts(priv->dvdnav)) // set vts domain
+          priv->status |= NAV_FLAG_VTS_DOMAIN;
+        else
+          priv->status &= ~NAV_FLAG_VTS_DOMAIN;
+
+        nextstill = dvdnav_get_next_still_flag(priv->dvdnav);
+        if(nextstill==0xff) {
+          priv->duration = 0;
+          priv->still_length = nextstill;
+        } else if(nextstill) {
+          priv->duration = nextstill * 1000;
+          priv->still_length = nextstill;
+        }
+        dvdnav_get_highlight (priv, 1);
         break;
       }
       case DVDNAV_SPU_CLUT_CHANGE: {
         memcpy(priv->spu_clut, buf, 16*sizeof(unsigned int));
-        priv->spu_set = 1;
+        priv->status |= NAV_FLAG_SPU_SET;       // spu clut valid
         break;
       }
-      case DVDNAV_WAIT:
+      case DVDNAV_WAIT: {
+        // if don't open demuxer then suspend read in dvdnav stream
+        // else wait skip
+        if ((priv->status & NAV_FLAG_WAIT_SKIP) &&
+            !(priv->status & NAV_FLAG_WAIT))
         dvdnav_wait_skip(priv->dvdnav);
+        else
+          priv->status |= NAV_FLAG_WAIT;
+        break;
+      }
+      case DVDNAV_VTS_CHANGE: {
+        priv->status &= ~NAV_FLAG_WAIT_SKIP;
+        priv->status |= NAV_FLAG_STREAM_CHANGE; // changed stream
+        break;
+      }
+      case DVDNAV_SPU_STREAM_CHANGE: {
+        priv->status |= NAV_FLAG_STREAM_CHANGE; // changed stream
+        priv->status |= NAV_FLAG_SPU_CHANGE;    // changed SPU
         break;
     }
+    }
 
     *len=0;
   }
@@ -231,6 +278,11 @@
     int event;
 
     dvdnav_priv_t* priv=s->priv;
+    // is suspend read
+    if (priv->status & NAV_FLAG_WAIT_READ) {
+      len=-1;
+      return len;
+    }
     len=0;
     if(!s->end_pos)
       update_title_len(s);
@@ -243,16 +295,29 @@
         return 0;
       }
       switch (event) {
-        case DVDNAV_STOP:
+        case DVDNAV_STOP: {
+          priv->status |= NAV_FLAG_EOFSTREAM;   // really eof
+          return len;
+        }
         case DVDNAV_BLOCK_OK:
         case DVDNAV_NAV_PACKET:
           return len;
+        case DVDNAV_STILL_FRAME: return len;
+        case DVDNAV_WAIT: {                     // wait active
+          if (priv->status & NAV_FLAG_WAIT) return len;
+          break;
+        }
         case DVDNAV_VTS_CHANGE: {
           int tit = 0, part = 0;
           dvdnav_vts_change_event_t *vts_event = (dvdnav_vts_change_event_t *)s->buffer;
           mp_msg(MSGT_CPLAYER,MSGL_INFO, "DVDNAV, switched to title: %d\r\n", vts_event->new_vtsN);
+          priv->status |= NAV_FLAG_CELL_CHANGE; // changed stream
+          priv->status &= ~NAV_FLAG_WAIT_SKIP;  // clear
+          priv->status &= ~NAV_FLAG_WAIT;
           s->end_pos = 0;
           update_title_len(s);
+          if (priv->status & NAV_FLAG_WAIT_READ_AUTO)
+            priv->status |= NAV_FLAG_WAIT_READ; // skip read from dvdnav stream
           if(dvdnav_current_title_info(priv->dvdnav, &tit, &part) == DVDNAV_STATUS_OK) {
             mp_msg(MSGT_CPLAYER,MSGL_V, "\r\nDVDNAV, NEW TITLE %d\r\n", tit);
             dvdnav_get_highlight (priv, 0);
@@ -262,6 +327,11 @@
           break;
         }
         case DVDNAV_CELL_CHANGE: {
+          priv->status |= NAV_FLAG_CELL_CHANGE; // changed stream
+          priv->status &= ~NAV_FLAG_WAIT_SKIP;  // clear
+          priv->status &= ~NAV_FLAG_WAIT;
+          if (priv->status & NAV_FLAG_WAIT_READ_AUTO)
+            priv->status |= NAV_FLAG_WAIT_READ; // skip read from dvdnav stream
           if(priv->title > 0 && dvd_last_chapter > 0) {
             int tit=0, part=0;
             if(dvdnav_current_title_info(priv->dvdnav, &tit, &part) == DVDNAV_STATUS_OK && part > dvd_last_chapter)
@@ -311,7 +381,7 @@
     }
     case STREAM_CTRL_GET_TIME_LENGTH:
     {
-      if(priv->duration)
+      if (priv->duration || priv->still_length)
       {
         *((double *)arg) = (double)priv->duration / 1000.0;
         return 1;
@@ -374,10 +444,8 @@
     }
     if(dvd_chapter > 0)
       dvdnav_part_play(priv->dvdnav, p->track, dvd_chapter);
-  } else if(p->track == -1)
-    dvdnav_menu_call(priv->dvdnav, DVD_MENU_Root);
-  else {
-    mp_msg(MSGT_OPEN,MSGL_INFO,"dvdnav_stream, you didn't specify a track number (as in dvdnav://1), playing whole disc\n");
+  } else if (p->track == 0) {
+    if(dvdnav_menu_call(priv->dvdnav, DVD_MENU_Root) != DVDNAV_STATUS_OK)
     dvdnav_menu_call(priv->dvdnav, DVD_MENU_Title);
   }
   if(dvd_angle > 1)
@@ -394,7 +462,7 @@
   *file_format = DEMUXER_TYPE_MPEG_PS;
 
   update_title_len(stream);
-  if(!stream->pos)
+  if(!stream->pos && p->track>0)
     mp_msg(MSGT_OPEN,MSGL_ERR, "INIT ERROR: couldn't get init pos %s\r\n", dvdnav_err_to_string(priv->dvdnav));
 
   mp_msg(MSGT_OPEN,MSGL_INFO, "Remember to disable MPlayer's cache when playing dvdnav:// streams (adding -nocache to your command line)\r\n");
@@ -403,15 +471,14 @@
 }
 
 
-int mp_dvdnav_handle_input(stream_t *stream, int cmd, int *button) {
+void mp_dvdnav_handle_input(stream_t *stream, int cmd, int *button) {
   dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
   dvdnav_t *nav = priv->dvdnav;
   dvdnav_status_t status=DVDNAV_STATUS_ERR;
   pci_t *pci = dvdnav_get_current_nav_pci(nav);
-  int reset = 0;
 
   if(cmd != MP_CMD_DVDNAV_SELECT && !pci)
-    return 0;
+    return;
 
   switch(cmd) {
     case MP_CMD_DVDNAV_UP:
@@ -428,26 +495,22 @@
       break;
     case MP_CMD_DVDNAV_MENU:
       status = dvdnav_menu_call(nav,DVD_MENU_Root);
-      reset = 1;
       break;
     case MP_CMD_DVDNAV_PREVMENU: {
       int title=0, part=0;
 
       dvdnav_current_title_info(nav, &title, &part);
       if(title) {
-        if(dvdnav_menu_call(nav, DVD_MENU_Part) == DVDNAV_STATUS_OK
-           || dvdnav_menu_call(nav, DVD_MENU_Title) == DVDNAV_STATUS_OK) {
-          reset = 1;
+        if((status=dvdnav_menu_call(nav, DVD_MENU_Part)) == DVDNAV_STATUS_OK)
+          break;
+        if((status=dvdnav_menu_call(nav, DVD_MENU_Title)) == DVDNAV_STATUS_OK)
           break;
         }
-      }
-      if(dvdnav_menu_call(nav, DVD_MENU_Root) == DVDNAV_STATUS_OK)
-        reset = 1;
+      status=dvdnav_menu_call(nav, DVD_MENU_Root);
       }
       break;
     case MP_CMD_DVDNAV_SELECT:
       status = dvdnav_button_activate(nav, pci);
-      if(status == DVDNAV_STATUS_OK) reset = 1;
       break;
     case MP_CMD_DVDNAV_MOUSECLICK:
       /*
@@ -458,7 +521,6 @@
         This last call always works well
       */
       status = dvdnav_mouse_activate(nav, pci, priv->mousex, priv->mousey);
-      if(status == DVDNAV_STATUS_OK) reset = 1;
       break;
     default:
       mp_msg(MSGT_CPLAYER, MSGL_V, "Unknown DVDNAV cmd %d\n", cmd);
@@ -468,7 +530,7 @@
   if(status == DVDNAV_STATUS_OK)
     dvdnav_get_current_highlight(nav, button);
 
-  return reset;
+  return;
 }
 
 void mp_dvdnav_update_mouse_pos(stream_t *stream, int32_t x, int32_t y, int* button) {
@@ -530,6 +592,41 @@
 }
 
 /**
+ * \brief dvdnav_aid_from_audio_num() returns the audio id corresponding to the logical number
+ * \param stream: - stream pointer
+ * \param audio_num: logical number
+ * \return -1 on error, current subtitle id if successful
+ */
+int dvdnav_aid_from_audio_num(stream_t *stream, int audio_num) {
+  dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+  int k;
+  uint8_t format, lg;
+
+#ifdef DVDNAV_FORMAT_AC3
+  //this macro is defined only in libdvdnav-cvs
+  for(k=0; k<32; k++) {
+    lg = dvdnav_get_audio_logical_stream(priv->dvdnav, k);
+    if(lg == 0xff) continue;
+    if(lg != audio_num) continue;
+    format = dvdnav_audio_stream_format(priv->dvdnav, lg);
+    switch(format) {
+      case DVDNAV_FORMAT_AC3:
+        return k+128;
+      case DVDNAV_FORMAT_DTS:
+        return k+136;
+      case DVDNAV_FORMAT_LPCM:
+        return k+160;
+      case DVDNAV_FORMAT_MPEGAUDIO:
+        return k;
+      default:
+        return -1;
+    }
+  }
+#endif
+  return -1;
+}
+
+/**
  * \brief dvdnav_lang_from_aid() assigns to buf the language corresponding to audio id 'aid'
  * \param stream: - stream pointer
  * \param sid: physical subtitle id
@@ -626,8 +723,8 @@
  */
 unsigned int *mp_dvdnav_get_spu_clut(stream_t *stream) {
     dvdnav_priv_t *priv=(dvdnav_priv_t*)stream->priv;
-    if(!priv->spu_set) return NULL;
-    return priv->spu_clut;
+    if (!(priv->status & NAV_FLAG_SPU_SET)) return NULL;    // invalid spu clut
+    return priv->spu_clut;  // valid spu clut
 }
 
 /**
@@ -639,10 +736,169 @@
   dvdnav_priv_t *priv = (dvdnav_priv_t *) stream->priv;
   dvdnav_highlight_event_t hlev = priv->hlev;
 
+  dvdnav_get_highlight (priv, 1);
   hl->sx = hlev.sx;
   hl->sy = hlev.sy;
   hl->ex = hlev.ex;
   hl->ey = hlev.ey;
+  hl->palette = hlev.palette;
+}
+
+/**
+ * \brief mp_dvdnav_isreallyeof() get really EOF flag
+ * \param stream: - stream pointer
+ * \return 1 on really eof
+ */
+int mp_dvdnav_isreallyeof(stream_t *stream) {
+    return ((dvdnav_priv_t*) stream->priv )->status &
+        NAV_FLAG_EOFSTREAM;
+}
+
+/**
+ * \brief mp_dvdnav_still_skip() call still skip
+ * \param stream: - stream pointer
+ * \return 0 on success
+ */
+int mp_dvdnav_still_skip(stream_t *stream) {
+  dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+  if (priv->still_length==0xff) return 1;
+  dvdnav_still_skip(priv->dvdnav);
+  return 0;
+}
+
+/**
+ * \brief mp_dvdnav_wait_skip() call wait skip
+ * \param stream: - stream pointer
+ * \return 0 on success
+ */
+int mp_dvdnav_wait_skip(stream_t *stream) {
+  dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+  if (!(priv->status & NAV_FLAG_WAIT)) return 1;
+  priv->status &= ~NAV_FLAG_WAIT;
+  dvdnav_wait_skip(priv->dvdnav);
+  return 0;
+}
+
+/**
+ * \brief mp_dvdnav_iscellchage() get cell change flag and clear this flag
+ * \param stream: - stream pointer
+ * \param clear : - if true then clear cell change flag
+ * \return 1 if cell change
+ */
+int mp_dvdnav_iscellchage(stream_t *stream, int clear) {
+  dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+  if (!(priv->status & NAV_FLAG_CELL_CHANGE)) return 0;
+  if (clear) priv->status &= ~NAV_FLAG_CELL_CHANGE;
+  return 1;
+}
+
+/**
+ * \brief mp_dvdnav_wait_read() set wait mode
+ * \param stream  : - stream pointer
+ * \param mode    : - if true then suspend block read
+ * \param automode: - if true then vts or cell change set wait mode
+ */
+void mp_dvdnav_wait_read(stream_t *stream, int mode, int automode) {
+  dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+  if (mode==0) priv->status &= ~NAV_FLAG_WAIT_READ;
+  if (mode>0) priv->status |= NAV_FLAG_WAIT_READ;
+  if (automode==0) priv->status &= ~NAV_FLAG_WAIT_READ_AUTO;
+  if (automode>0) priv->status |= NAV_FLAG_WAIT_READ_AUTO;
+  return;
+}
+
+// get current audio channel id
+int mp_dvdnav_get_audio(stream_t *stream) {
+    dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+    return dvdnav_get_active_audio_stream(priv->dvdnav);
+}
+
+audio_attr_t mp_dvdnav_audio_attr(stream_t *stream, int audio_num) {
+    audio_attr_t audio_attr;
+    dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+    memset(&audio_attr,0,sizeof(audio_attr_t));
+    dvdnav_get_audio_attr(priv->dvdnav, audio_num, &audio_attr);
+    return audio_attr;
+}
+
+// get current spu
+int mp_dvdnav_get_spu(stream_t *stream) {
+    dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+    return dvdnav_get_active_spu_stream(priv->dvdnav);
+}
+
+// is audio channel change?
+int mp_dvdnav_is_audio_change(stream_t *stream) {
+    dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+    if(!priv->status & NAV_FLAG_AUDIO_CHANGE) return 0;
+    priv->status &= ~NAV_FLAG_AUDIO_CHANGE;
+    return 1;
+}
+
+// is spu change?
+int mp_dvdnav_is_spu_change(stream_t *stream) {
+    dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+    if(!(priv->status & NAV_FLAG_SPU_CHANGE)) return 0;
+    priv->status &= ~NAV_FLAG_SPU_CHANGE;
+    return 1;
+}
+
+// is change title, part, audio or spu
+int mp_dvdnav_is_change(stream_t *stream) {
+    int tit = 0, part = 0, tit_nr = 0, part_nr = 0;
+    audio_attr_t audio_attr;
+    int i,sub_id,audio_id;
+    uint16_t language;
+    
+    dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+    if(!(priv->status & NAV_FLAG_STREAM_CHANGE)) return 0;	// no change
+    priv->status &= ~NAV_FLAG_STREAM_CHANGE;
+    dvdnav_current_title_info(priv->dvdnav, &tit, &part);	// get curren title and part
+    dvdnav_get_number_of_titles(priv->dvdnav,&tit_nr);
+    dvdnav_get_number_of_parts(priv->dvdnav,tit,&part_nr);
+    priv->titles_nr = tit_nr;		// update titles numbers
+    priv->chapters_nr = part_nr;	// update chapters numbers
+    priv->title=tit;			// update current title
+    priv->part=part;			// update current chapter
+    priv->nr_of_subtitles=0;
+    priv->nr_of_channels=0;
+    if (!(priv->status & NAV_FLAG_VTS_DOMAIN)) return 1;	// if no vts then no set audio and spu
+    for(i=0;i<32;i++) {			// updates spu's
+	    priv->subtitles[priv->nr_of_subtitles].id=-1;
+        if (-1==(sub_id=dvdnav_get_spu_logical_stream(priv->dvdnav,i))) continue;
+	    language=dvdnav_spu_stream_to_lang(priv->dvdnav, sub_id);
+	    priv->subtitles[priv->nr_of_subtitles].language=language;
+	    priv->subtitles[priv->nr_of_subtitles].id=sub_id;
+	    priv->nr_of_subtitles++;
+	}
+    for(i=0;i<32;i++) {			// updates audio channels
+	    priv->audio_streams[priv->nr_of_channels].id=-1;
+        if (-1==(sub_id=dvdnav_get_audio_logical_stream(priv->dvdnav,i))) continue;
+	    language=dvdnav_audio_stream_to_lang(priv->dvdnav, sub_id);
+        audio_id = dvdnav_aid_from_audio_num(stream, sub_id);
+        memset(&audio_attr,0,sizeof(audio_attr_t));
+        dvdnav_get_audio_attr(priv->dvdnav, i, &audio_attr);
+	    priv->audio_streams[priv->nr_of_channels].language=language;
+	    priv->audio_streams[priv->nr_of_channels].id=audio_id;
+	    priv->audio_streams[priv->nr_of_channels].type=audio_attr.audio_format;
+	    priv->audio_streams[priv->nr_of_channels].channels=audio_attr.channels;
+	    priv->nr_of_channels++;
+	}
+    return 1;
+}
+
+void mp_dvdnav_switch_title(stream_t *stream, int title) {
+    dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+
+    if(title>0 && title<=priv->titles_nr)
+        dvdnav_title_play(priv->dvdnav, title);
+}
+
+void mp_dvdnav_switch_chapter(stream_t *stream, int chapter) {
+    dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+
+    if(chapter>=0 && chapter<priv->chapters_nr && priv->title>0)
+        dvdnav_part_play(priv->dvdnav, priv->title, chapter);
 }
 
 stream_info_t stream_info_dvdnav = {
--- stream/stream_dvdnav.h	2007-10-07 21:49:26.000000000 +0200
+++ stream/stream_dvdnav.h	2007-10-23 16:41:30.000000000 +0200
@@ -12,27 +12,67 @@
 typedef struct {
   uint16_t sx, sy;
   uint16_t ex, ey;
+
+  uint32_t palette;
 } nav_highlight_t;
 
+/* status flags */
+#define NAV_FLAG_EOFSTREAM      0x0001  /* stream eof flag */
+#define NAV_FLAG_WAIT           0x0002  /* wait event */
+#define NAV_FLAG_WAIT_SKIP      0x0004  /* wait skip disable */
+#define NAV_FLAG_CELL_CHANGE    0x0008  /* cell change event */
+#define NAV_FLAG_WAIT_READ_AUTO 0x0010  /* wait read auto mode (if opening demuxer then off else on) */
+#define NAV_FLAG_WAIT_READ      0x0020  /* wait read flag (suspend read from dvdnav stream */
+#define NAV_FLAG_STREAM_CHANGE  0x0040  /* stream change flag: title, part, audio or SPU */
+#define NAV_FLAG_VTS_DOMAIN     0x0080  /* vts domain */
+#define NAV_FLAG_SPU_SET        0x0100  /* spu_clut is valid */
+#define NAV_FLAG_SPU_CHANGE     0x0200  /* SPU change flag */
+#define NAV_FLAG_AUDIO_CHANGE   0x0400  /* audio change flag */
+
 typedef struct {
   dvdnav_t *       dvdnav;              /* handle to libdvdnav stuff */
   char *           filename;            /* path */
   unsigned int     duration;            /* in milliseconds */
   int              mousex, mousey;
   int              title;
-  unsigned int     spu_clut[16], spu_set;
+  unsigned int     spu_clut[16];
   dvdnav_highlight_event_t hlev;
+  int              still_length;        /* still frame duration */
+  unsigned int     status;
+
+  int		   part;		/* current chapter */
+  int		   titles_nr;		/* all titles numbers */
+  int		   chapters_nr;		/* all chapert numbers in current title */
+  int		   nr_of_channels;	/* audio channels numbers */
+  stream_language_t audio_streams[32];	/* audio channels propreties */
+  int		   nr_of_subtitles;	/* spu numbers */
+  stream_language_t subtitles[32];	/* spu properties */
 } dvdnav_priv_t;
 
 
 int dvdnav_number_of_subs(stream_t *stream);
 int dvdnav_aid_from_lang(stream_t *stream, unsigned char *language);
+int dvdnav_aid_from_audio_num(stream_t *stream, int audio_num);
 int dvdnav_lang_from_aid(stream_t *stream, int id, unsigned char *buf);
 int dvdnav_sid_from_lang(stream_t *stream, unsigned char *language);
 int dvdnav_lang_from_sid(stream_t *stream, int sid, unsigned char *buf);
-int mp_dvdnav_handle_input(stream_t *stream, int cmd, int *button);
+void mp_dvdnav_handle_input(stream_t *stream, int cmd, int *button);
 void mp_dvdnav_update_mouse_pos(stream_t *stream, int32_t x, int32_t y, int* button);
 void mp_dvdnav_get_highlight (stream_t *stream, nav_highlight_t *hl);
 unsigned int *mp_dvdnav_get_spu_clut(stream_t *stream);
+int mp_dvdnav_isreallyeof(stream_t *stream);
+int mp_dvdnav_still_skip(stream_t *stream);
+int mp_dvdnav_wait_skip(stream_t *stream);
+int mp_dvdnav_iscellchage(stream_t *stream, int clear);
+void mp_dvdnav_wait_read(stream_t *stream, int mode, int automode);
+
+int mp_dvdnav_get_audio(stream_t *stream);
+audio_attr_t mp_dvdnav_audio_attr(stream_t *stream, int audio_num);
+int mp_dvdnav_is_audio_change(stream_t *stream);
+int mp_dvdnav_get_spu(stream_t *stream);
+int mp_dvdnav_is_spu_change(stream_t *stream);
+int mp_dvdnav_is_change(stream_t *stream);
 
+void mp_dvdnav_switch_title(stream_t *stream, int title);
+void mp_dvdnav_switch_chapter(stream_t *stream, int chapter);
 #endif
