--- mplayer.c	 (revision 22492)
+++ mplayer.c	 (working copy)
@@ -92,6 +92,40 @@
 
 #define ROUND(x) ((int)((x)<0 ? (x)-0.5 : (x)+0.5))
 
+#ifdef USE_DVDNAV
+#include "libmpcodecs/img_format.h"
+#include "libmpcodecs/mp_image.h"
+#include "libvo/fastmemcpy.h"
+int dvdnav_color_spu_flg = -1;
+int dvdnav_color_spu = 1;
+
+unsigned char emptyframe[371] = {
+    0x00,0x00,0x01,0x00,0x03,0x17,0xff,0xfb,0x80,0x00,0x00,0x01,0xb5,0x81,0x1f,0xf3,
+    0x41,0x80,0x00,0x00,0x01,0x01,0x12,0x70,0x10,0x14,0x70,0x00,0x00,0x01,0x02,0x12,
+    0x70,0x10,0x14,0x70,0x00,0x00,0x01,0x03,0x12,0x70,0x10,0x14,0x70,0x00,0x00,0x01,
+    0x04,0x12,0x70,0x10,0x14,0x70,0x00,0x00,0x01,0x05,0x12,0x70,0x10,0x14,0x70,0x00,
+    0x00,0x01,0x06,0x12,0x70,0x10,0x14,0x70,0x00,0x00,0x01,0x07,0x12,0x70,0x10,0x14,
+    0x70,0x00,0x00,0x01,0x08,0x12,0x76,0xe1,0x3a,0x01,0x01,0x8e,0x00,0x00,0x01,0x09,
+    0x12,0x70,0x10,0x14,0x70,0x00,0x00,0x01,0x0a,0x12,0x70,0x10,0x14,0x70,0x00,0x00,
+    0x01,0x0b,0x12,0x70,0x10,0x14,0x70,0x00,0x00,0x01,0x0c,0x12,0x70,0x38,0xe1,0x3e,
+    0x06,0x38,0x00,0x00,0x01,0x0d,0x12,0x70,0x10,0x26,0x80,0xe4,0x67,0x00,0x00,0x01,
+    0x0e,0x12,0x70,0x10,0x14,0x70,0x00,0x00,0x01,0x0f,0x12,0x70,0x10,0x14,0x70,0x00,
+    0x00,0x01,0x10,0x12,0x70,0x49,0xd0,0x67,0xff,0xf8,0x11,0x1c,0x00,0x00,0x01,0x11,
+    0x12,0x70,0x11,0x70,0x0e,0x41,0x67,0x00,0x00,0x01,0x12,0x12,0x74,0xe8,0x1c,0x93,
+    0x40,0xce,0x00,0x30,0x08,0x23,0x80,0x00,0x00,0x01,0x13,0x12,0x70,0x67,0x00,0xec,
+    0x07,0x0e,0x00,0x00,0x01,0x14,0x12,0x70,0x10,0x14,0x70,0x00,0x00,0x01,0x15,0x12,
+    0x70,0x4d,0xa0,0x39,0x02,0x13,0x80,0x00,0x00,0x01,0x16,0x12,0x70,0x55,0xa0,0x3b,
+    0x01,0xf3,0x80,0x00,0x00,0x01,0x17,0x12,0x70,0x10,0x14,0x70,0x00,0x00,0x01,0x18,
+    0x12,0x70,0x10,0x14,0x70,0x00,0x00,0x01,0x19,0x12,0x70,0x10,0x14,0x70,0x00,0x00,
+    0x01,0x1a,0x12,0x70,0x10,0x14,0x70,0x00,0x00,0x01,0x1b,0x12,0x70,0x10,0x14,0x70,
+    0x00,0x00,0x01,0x1c,0x12,0x70,0x10,0x14,0x70,0x00,0x00,0x01,0x1d,0x12,0x70,0x10,
+    0x14,0x70,0x00,0x00,0x01,0x1e,0x12,0x70,0x10,0x6e,0x13,0xe1,0x1c,0x00,0x00,0x01,
+    0x1f,0x12,0x70,0x10,0x14,0x70,0x00,0x00,0x01,0x20,0x12,0x70,0x10,0x14,0x70,0x00,
+    0x00,0x01,0x21,0x12,0x70,0x10,0x14,0x70,0x00,0x00,0x01,0x22,0x12,0x70,0x10,0x14,
+    0x70,0x00,0x00,0x01,0x23,0x12,0x70,0x10,0x14,0x70,0x00,0x00,0x01,0x24,0x12,0x70,
+    0x10,0x14,0x70};
+#endif
+
 #ifdef HAVE_RTC
 #ifdef __linux__
 #include <linux/rtc.h>
@@ -203,6 +237,9 @@
 #ifdef HAS_DVBIN_SUPPORT
     .last_dvb_step = 1,
 #endif
+#ifdef USE_DVDNAV
+    .dvdnav_last_audio_id=-1,
+#endif
 };
 
 int fixed_vo=0;
@@ -617,6 +654,14 @@
     current_module="uninit_vo";
     mpctx->video_out->uninit();
     mpctx->video_out=NULL;
+#ifdef USE_DVDNAV
+    if(mpctx->smpi) free_mp_image(mpctx->smpi);
+    mpctx->smpi=NULL;
+    if(mpctx->last_buffer) free(mpctx->last_buffer);
+    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.
@@ -1012,6 +1057,7 @@
   if (vo_spudec==NULL && mpctx->stream->type==STREAMTYPE_DVDNAV) {
     unsigned int *palette = mp_dvdnav_get_spu_clut(mpctx->stream);
     current_module="spudec_init_dvdnav";
+    palette=NULL;
     vo_spudec=spudec_new_scaled(palette, mpctx->sh_video->disp_w, mpctx->sh_video->disp_h);
   }
 #endif
@@ -1680,6 +1726,275 @@
     return time_frame;
 }
 
+// DVDNAV *FIXME*
+#ifdef USE_DVDNAV
+inline static void copy_mpi(mp_image_t *dmpi, mp_image_t *mpi) {
+    if(mpi->flags&MP_IMGFLAG_PLANAR){
+	memcpy_pic(dmpi->planes[0],mpi->planes[0], mpi->w, mpi->h,
+	       dmpi->stride[0],mpi->stride[0]);
+	memcpy_pic(dmpi->planes[1],mpi->planes[1], mpi->chroma_width, mpi->chroma_height,
+	       dmpi->stride[1],mpi->stride[1]);
+	memcpy_pic(dmpi->planes[2], mpi->planes[2], mpi->chroma_width, mpi->chroma_height,
+	       dmpi->stride[2],mpi->stride[2]);
+    } else {
+	memcpy_pic(dmpi->planes[0],mpi->planes[0],
+	       mpi->w*(dmpi->bpp/8), mpi->h,
+	       dmpi->stride[0],mpi->stride[0]);
+    }
+}
+
+mp_image_t* mp_dvdnav_copympi(mp_image_t* tompi, mp_image_t* frommpi) {
+    if(!frommpi) return NULL;
+    mp_image_t* mpi;
+    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=new_mp_image(frommpi->w,frommpi->h);
+	if(!mpi) return NULL;
+	mp_image_setfmt(mpi,frommpi->imgfmt);
+	if (mpi->imgfmt == IMGFMT_IF09)
+	    {
+    	    mpi->planes[0]=memalign(64, mpi->bpp*mpi->width*(mpi->height+2)/8+
+			      mpi->chroma_width*mpi->chroma_height);
+	    /* delta table, just for fun ;) */
+	    mpi->planes[3]=mpi->planes[0]+2*(mpi->chroma_width*mpi->chroma_height);
+    	    }
+	    else
+	    mpi->planes[0]=memalign(64, mpi->bpp*mpi->width*(mpi->height+2)/8);
+	if(mpi->flags&MP_IMGFLAG_PLANAR){
+	    // YV12/I420/YVU9/IF09. feel free to add other planar formats here...
+	    if(!mpi->stride[0]) mpi->stride[0]=mpi->width;
+	    if(!mpi->stride[1]) mpi->stride[1]=mpi->stride[2]=mpi->chroma_width;
+	    if(mpi->flags&MP_IMGFLAG_SWAPPED){
+		// I420/IYUV  (Y,U,V)
+		mpi->planes[1]=mpi->planes[0]+mpi->width*mpi->height;
+		mpi->planes[2]=mpi->planes[1]+mpi->chroma_width*mpi->chroma_height;
+		} else {
+		// YV12,YVU9,IF09  (Y,V,U)
+		mpi->planes[2]=mpi->planes[0]+mpi->width*mpi->height;
+		mpi->planes[1]=mpi->planes[2]+mpi->chroma_width*mpi->chroma_height;
+		}
+	    } else {
+	    if(!mpi->stride[0]) mpi->stride[0]=mpi->width*mpi->bpp/8;
+	    }
+	}
+    mpi->flags|=MP_IMGFLAG_ALLOCATED;
+    copy_mpi(mpi,frommpi);
+    return mpi;
+}
+
+static void* mp_dvdnav_decode_video_pre(int *in_size, unsigned char **start, 
+	mp_image_t* decoded_frame) {
+if (mp_dvdnav_iscellchage(mpctx->stream,0)) {
+    mp_dvdnav_wait_read(mpctx->stream, 1, 1);
+    if(mpctx->smpi) free_mp_image(mpctx->smpi);
+    mpctx->smpi=NULL;
+    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 (mpctx->sh_video) {
+        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;
+        }
+    if (mpctx->sh_audio) {
+        ds_free_packs(mpctx->d_audio);
+        audio_delay -= mpctx->sh_audio->stream_delay;
+        mpctx->sh_audio->delay=-audio_delay;
+        mpctx->audio_out->reset();
+        resync_audio_stream(mpctx->sh_audio);
+        }
+    mpctx->sh_video->timer=0;
+    audio_delay=0.0f;
+    correct_pts=0;
+    mpctx->d_video->eof=mpctx->d_audio->eof=mpctx->stream->eof=0;
+    mp_dvdnav_wait_read(mpctx->stream, 0, 1);
+    mp_dvdnav_iscellchage(mpctx->stream,1);
+    }
+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;
+#ifdef VDCTRL_SET_CODEC_FLAG_LOW_DELAY
+	vd_set_codec_flag_low_delay(mpctx->sh_video, 1);
+#endif
+	}
+    if (mpctx->last_start) {
+    	*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;
+}
+
+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) {
+
+if(in_size<0) {
+    if (mpctx->last_buffer) {
+	free(mpctx->last_buffer);
+	mpctx->last_buffer=NULL;
+	mpctx->last_in_size=0;
+	}
+    float len = demuxer_get_time_length(mpctx->demuxer);
+    if ((mpctx->sh_video->pts>=len || !mpctx->smpi) && mpctx->sh_video->pts>0.0) {
+	mp_dvdnav_still_skip(mpctx->stream);
+	mp_dvdnav_wait_skip(mpctx->stream);
+	}
+    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) {
+#ifdef VDCTRL_SET_CODEC_FLAG_LOW_DELAY
+	    vd_set_codec_flag_low_delay(mpctx->sh_video, 0);
+#endif
+	    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.\nPlease try to -vfm ffmpeg options.\n");
+		mpctx->eof=1;
+		}
+	    } else {
+	    if(!decoded_frame && mpctx->last_buffer) {
+    		start=mpctx->last_start;
+		memcpy(start,emptyframe,sizeof(emptyframe));
+		in_size=sizeof(emptyframe);
+		decoded_frame = decode_video(sh_video, start, in_size, drop_frame,
+				     sh_video->pts);
+		}
+	    }
+	} else {
+    	    if(mpctx->last_buffer) free(mpctx->last_buffer);
+	    mpctx->last_in_size=in_size;
+	    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_frame && mpctx->smpi!=decoded_frame) mpctx->smpi=mp_dvdnav_copympi(mpctx->smpi,decoded_frame);
+    }
+return decoded_frame; 
+}
+
+static int mp_dvdnav_audio_handle() {
+int dvdnav_audio=mp_dvdnav_get_audio(mpctx->stream);
+int current_id=mpctx->demuxer->audio->id;
+int i,demux_id,nav_id,res;
+
+res=-1;
+nav_id=mp_dvdnav_get_logical_audio(mpctx->stream, dvdnav_audio);
+for(i=0;i<8;i++) {
+    demux_id=i;
+    if(demux_control(mpctx->demuxer, DEMUXER_CTRL_GET_AUDIO, &demux_id)!=DEMUXER_CTRL_OK) continue;
+    if(demux_id==-1) continue;
+    if((demux_id & 0x0f)==(nav_id & 0x0f)) {res=demux_id; break;}
+    }
+dvdnav_audio=res;
+if(dvdnav_audio==-1) return;
+if(current_id==dvdnav_audio) return;
+audio_id = demuxer_switch_audio(mpctx->demuxer, dvdnav_audio);
+if (mpctx->dvdnav_last_audio_id==dvdnav_audio) return;
+mpctx->dvdnav_last_audio_id=dvdnav_audio;
+if((current_id & 0x0F)==(dvdnav_audio &0x0F)) return;
+
+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;
+}
+
+static void mp_dvdnav_highlight_handle(int stream_is_change) {
+nav_highlight_t highlight;
+spu_clut_t *spu_clut;
+
+if (!dvdnav_color_spu) return;
+if (dvdnav_color_spu_flg==-1) {
+    dvdnav_color_spu_flg=0;
+    if (mpctx->video_out) {
+        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) {
+    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)) {
+	osd_set_nav_box(highlight.sx,highlight.sy,highlight.ex,highlight.ey);
+	vo_osd_changed(OSDTYPE_DVDNAV);
+	} else {
+	osd_set_nav_box(0,0,0,0);
+	vo_osd_changed(OSDTYPE_DVDNAV);
+	}
+    }
+}
+
+static void mp_dvdnav_spu_handle() {
+if(!mp_dvdnav_is_spu_change(mpctx->stream)) return;
+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;
+}
+
+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;
+}
+#endif
+
 static void adjust_sync_and_print_status(int between_frames, float timing_error)
 {
     current_module="av_sync";
@@ -2000,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;
 
@@ -2008,6 +2323,14 @@
 	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
+	if (mpctx->stream->type==STREAMTYPE_DVDNAV && in_size < 0) {
+	    if(mp_dvdnav_isreallyeof(mpctx->stream)) return -1;
+	    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)
@@ -2037,8 +2360,17 @@
 	update_subtitles(sh_video, mpctx->d_sub, 0);
 	update_osd_msg();
 	current_module = "decode_video";
+#ifdef USE_DVDNAV
+	if (mpctx->stream->type==STREAMTYPE_DVDNAV)
+	    decoded_frame=mp_dvdnav_decode_video_pre(&in_size,&start,decoded_frame);
+	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)
+	    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));
@@ -3341,6 +3673,15 @@
 }
 
 
+#ifdef USE_DVDNAV
+if(mpctx->smpi) free_mp_image(mpctx->smpi);
+mpctx->smpi=NULL;
+if (mpctx->stream->type==STREAMTYPE_DVDNAV) {
+    mp_dvdnav_wait_read(mpctx->stream, 0, 1);
+    mp_dvdnav_iscellchage(mpctx->stream,1);
+    }
+#endif
+
 while(!mpctx->eof){
     float aq_sleep_time=0;
 if(!mpctx->sh_audio && mpctx->d_audio->sh) {
@@ -3394,6 +3735,20 @@
       }
   }
 
+#ifdef USE_DVDNAV
+if (mpctx->stream->type==STREAMTYPE_DVDNAV) {
+    if (mp_dvdnav_is_stream_change()) {
+	mp_dvdnav_audio_handle();
+	mp_dvdnav_spu_handle();
+#ifdef HAVE_NEW_GUI
+	if ( use_gui ) guiGetEvent( guiSetStream,(char *)mpctx->stream );
+#endif
+	mp_dvdnav_highlight_handle(1);
+	}
+	else
+	mp_dvdnav_highlight_handle(0);
+    }
+#endif
 // ==========================================================================
     
 //    current_module="draw_osd";
@@ -3464,7 +3819,7 @@
 } // end if(mpctx->sh_video)
 
 #ifdef USE_DVDNAV
- if (mpctx->stream->type == STREAMTYPE_DVDNAV) {
+ if (mpctx->stream->type == STREAMTYPE_DVDNAV && 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);
--- mencoder.c	 (revision 22492)
+++ mencoder.c	 (working copy)
@@ -94,6 +94,7 @@
 int forced_subs_only=0;
 
 //--------------------------
+int dvdnav_color_spu = 0;
 
 // cache2:
 int stream_cache_size=-1;
--- command.c	 (revision 22492)
+++ command.c	 (working copy)
@@ -2355,14 +2355,28 @@
 
 		if (mp_dvdnav_handle_input
 		    (mpctx->stream, cmd->args[0].v.i, &button)) {
+#if 0
 		    uninit_player(INITED_ALL - (INITED_STREAM | INITED_INPUT |
 				   (fixed_vo ? INITED_VO : 0)));
 		    brk_cmd = 2;
+#endif
 		} else 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_play_title(mpctx->stream, cmd->args[0].v.i);
+	    }
+	    break;
+	case MP_CMD_SWITCH_CHAPTER:{
+		if (mpctx->stream->type != STREAMTYPE_DVDNAV)
+		    break;
+		mp_dvdnav_play_chapter(mpctx->stream, cmd->args[0].v.i);
+	    }
+	    break;
 #endif
 
 	default:
--- mp_core.h	 (revision 22492)
+++ mp_core.h	 (working copy)
@@ -91,6 +91,15 @@
 #endif
 
     int was_paused;
+#ifdef USE_DVDNAV
+    void *smpi;
+    void *last_buffer;
+    void *last_start;
+    int last_in_size;
+    int libmpeg2_count;
+    int dup_frame;
+    int dvdnav_last_audio_id;
+#endif
 } MPContext;
 
 
--- stream/stream_dvdnav.h	 (revision 22492)
+++ stream/stream_dvdnav.h	 (working copy)
@@ -12,8 +12,14 @@
 typedef struct {
   uint16_t sx, sy;
   uint16_t ex, ey;
+
+  uint32_t palette;
+  uint32_t pts;
+  uint32_t buttonN;
 } nav_highlight_t;
 
+typedef uint32_t spu_clut_t[16];
+
 typedef struct {
   dvdnav_t *       dvdnav;              /* handle to libdvdnav stuff */
   char *           filename;            /* path */
@@ -22,12 +28,33 @@
   unsigned int     sleep_until;         /* timer */
   int              started;             /* Has mplayer initialization finished? */
   unsigned int     duration;            /* in milliseconds */
+  unsigned int     start_pts;           /* in milliseconds */
   int              mousex, mousey;
   int              title;
   unsigned int     spu_clut[16], spu_set;
   dvdnav_highlight_event_t hlev;
+  int		   eofstream;		/* stream eof flag */
+  int		   still_length;
+  int		   wait;
+  int		   wait_skip;	/* wait skip disable */
+  int 		   cell_change;
+  int		   audio_change;
+  int		   spu_change;
+  int		   wait_read_automode;
+  int		   wait_read;
+  int		   stream_change;
+  int		   vts_domain;
+// with gui
+  int		   part;
+  int		   titles_nr;
+  int		   chapters_nr;
+  int		   nr_of_channels;
+  stream_language_t audio_streams[32];
+  int		   nr_of_subtitles;
+  stream_language_t subtitles[32];
 } dvdnav_priv_t;
 
+extern int dvdnav_color_spu;
 
 int dvdnav_number_of_subs(stream_t *stream);
 int dvdnav_aid_from_lang(stream_t *stream, unsigned char *language);
@@ -38,5 +65,17 @@
 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);
+int mp_dvdnav_get_logical_audio(stream_t *stream, int id);
+int mp_dvdnav_get_spu(stream_t *stream);
+int mp_dvdnav_is_audio_change(stream_t *stream);
+int mp_dvdnav_is_spu_change(stream_t *stream);
+int mp_dvdnav_is_change(stream_t *stream);
+void mp_dvdnav_play_title(stream_t *stream, int title);
+void mp_dvdnav_play_chapter(stream_t *stream, int chapter);
 #endif
--- stream/stream_dvdnav.c	 (revision 22492)
+++ stream/stream_dvdnav.c	 (working copy)
@@ -27,7 +27,7 @@
   int track;
   char* device;
 } stream_priv_dflts = {
-  0,
+  -1,
   NULL
 };
 
@@ -52,6 +52,7 @@
 static dvdnav_priv_t * new_dvdnav_stream(char * filename) {
   char * title_str;
   dvdnav_priv_t *priv;
+  int i;
 
   if (!filename)
     return NULL;
@@ -138,6 +139,18 @@
   }
 }
 
+static int dvdtimetomsec(dvd_time_t *dt)
+{
+  static int framerates[4] = {0, 2500, 0, 2997};
+  int framerate = framerates[(dt->frame_u & 0xc0) >> 6];
+  int msec = (((dt->hour & 0xf0) >> 3) * 5 + (dt->hour & 0x0f)) * 3600000;
+  msec += (((dt->minute & 0xf0) >> 3) * 5 + (dt->minute & 0x0f)) * 60000;
+  msec += (((dt->second & 0xf0) >> 3) * 5 + (dt->second & 0x0f)) * 1000;
+  if(framerate > 0)
+    msec += (((dt->frame_u & 0x30) >> 3) * 5 + (dt->frame_u & 0x0f)) * 100000 / framerate;
+  return msec;
+}
+
 static int dvdnav_stream_read(dvdnav_priv_t * priv, unsigned char *buf, int *len) {
   int event = DVDNAV_NOP;
 
@@ -165,8 +178,12 @@
         dvdnav_still_event_t *still_event = (dvdnav_still_event_t*)(buf);
         //if (priv->started) dvd_nav_still=1;
         //else
-          dvdnav_still_skip(priv->dvdnav); // don't let dvdnav stall on this image
-
+//          dvdnav_still_skip(priv->dvdnav); // don't let dvdnav stall on this image
+	priv->still_length=still_event->length;
+	if (priv->still_length && priv->still_length!=255)
+	    priv->duration = priv->still_length * 1000;
+	    else
+	    priv->duration = 0;
         break;
       }
       case DVDNAV_HIGHLIGHT: {
@@ -174,9 +191,25 @@
         break;
       }
       case DVDNAV_CELL_CHANGE: {
+	priv->wait_skip=0;
+	priv->audio_change = 1;
+	priv->spu_change = 1;
+	priv->stream_change = 1;
         dvdnav_cell_change_event_t *ev =  (dvdnav_cell_change_event_t*)buf;
         if(ev->pgc_length)
           priv->duration = ev->pgc_length/90;
+	priv->start_pts = ev->cell_start/90;
+	priv->vts_domain=dvdnav_is_domain_vts(priv->dvdnav);
+        break;
+      }
+      case DVDNAV_AUDIO_STREAM_CHANGE: {
+	priv->stream_change = 1;
+	priv->audio_change = 1;
+	break;
+      }
+      case DVDNAV_SPU_STREAM_CHANGE: {
+	priv->stream_change = 1;
+	priv->spu_change = 1;
         break;
       }
       case DVDNAV_SPU_CLUT_CHANGE: {
@@ -185,9 +218,17 @@
         break;
       }
       case DVDNAV_WAIT:
-        dvdnav_wait_skip(priv->dvdnav);
+//        dvdnav_wait_skip(priv->dvdnav);
+	if(priv->wait_skip && !priv->wait) dvdnav_wait_skip(priv->dvdnav); else priv->wait=1;
+        break;
+	case DVDNAV_VTS_CHANGE: {
+	    priv->wait_skip=0;
+	    priv->audio_change = 1;
+	    priv->spu_change = 1;
+	    priv->stream_change = 1;
         break;
     }
+    }
 
     *len=0;
   }
@@ -243,6 +284,7 @@
     int event;
 
     dvdnav_priv_t* priv=s->priv;
+    if(priv->wait_read) {len=-1; return len;}
     len=0;
     if(!s->end_pos)
       update_title_len(s);
@@ -255,23 +297,35 @@
         return 0;
       }
       switch (event) {
-        case DVDNAV_STOP:
+        case DVDNAV_STOP: { priv->eofstream=1; return len; }
         case DVDNAV_BLOCK_OK:
         case DVDNAV_NAV_PACKET:
           return len;
+	case DVDNAV_STILL_FRAME: return len;
+	case DVDNAV_WAIT: { if(priv->wait) return len; break; }
         case DVDNAV_VTS_CHANGE: {
           int tit = 0, part = 0;
+	    priv->cell_change=1;
+	    priv->wait_skip=0;
+	    priv->wait=0;
           s->end_pos = 0;
+	  priv->start_pts = 0;
           update_title_len(s);
+	  if(priv->wait_read_automode) priv->wait_read=1;
           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);
-            if(priv->title > 0 && tit != priv->title)
+            if(priv->title > 0 && tit != priv->title) {
               return 0;
           }
+          }
           break;
         }
         case DVDNAV_CELL_CHANGE: {
+	    priv->cell_change=1;
+	    priv->wait_skip=0;
+	    priv->wait=0;
+	    if(priv->wait_read_automode) priv->wait_read=1;
           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)
@@ -328,6 +382,28 @@
       }
       break;
     }
+    case STREAM_CTRL_GET_CURRENT_TIME:
+    {
+	double tm = MP_NOPTS_VALUE;
+	if (!priv->vts_domain) {
+	    tm += 1.0f;
+	    *((double *)arg) = tm;
+	    return 1;
+	    }
+	dsi_t* pnavdsi = NULL;
+	if (!(pnavdsi = dvdnav_get_current_nav_dsi (priv->dvdnav)))
+	    return STREAM_UNSUPORTED;
+	dvd_time_t *c_eltm;
+	c_eltm = &(pnavdsi->dsi_gi.c_eltm);
+	tm = priv->start_pts;
+	tm += dvdtimetomsec( c_eltm );
+	tm = tm / 1000.0f;
+        if(tm != -1) {
+          *((double *)arg) = tm;
+          return 1;
+        }
+        break;
+    }
   }
 
   return STREAM_UNSUPORTED;
@@ -361,12 +437,12 @@
     }
     if(dvd_chapter > 0)
       dvdnav_part_play(priv->dvdnav, p->track, dvd_chapter);
-  } else if(p->track == -1)
+  } else if(p->track == 0)
     dvdnav_menu_call(priv->dvdnav, DVD_MENU_Root);
-  else {
+  /*else {	// **FIXME** disable to test still frame with still_length
     mp_msg(MSGT_OPEN,MSGL_INFO,"dvdnav_stream, you didn't specify a track number (as in dvdnav://1), playing whole disc\n");
     dvdnav_menu_call(priv->dvdnav, DVD_MENU_Title);
-  }
+  }*/
   if(dvd_angle > 1)
     dvdnav_angle_change(priv->dvdnav, dvd_angle);
 
@@ -379,9 +455,8 @@
   stream->type = STREAMTYPE_DVDNAV;
   stream->priv=(void*)priv;
   *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: %d, couldn't get init pos %s\r\n", status, 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");
@@ -445,6 +520,7 @@
         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);
@@ -615,10 +691,160 @@
   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;
+  hl->pts = hlev.pts;
+  hl->buttonN = hlev.buttonN;
+}
+
+// dvdnav stream is really eof or still,wait,etc.
+int mp_dvdnav_isreallyeof(stream_t *stream) {
+    dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+    return priv->eofstream;
+}
+
+int mp_dvdnav_still_skip(stream_t *stream) {
+    dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+    if (priv->still_length==0 || priv->still_length==255) return 0;
+    dvdnav_still_skip(priv->dvdnav);
+    return 1;
+}
+
+int mp_dvdnav_wait_skip(stream_t *stream) {
+    dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+    if (!priv->wait) return 0;
+    priv->wait=0;
+    dvdnav_wait_skip(priv->dvdnav);
+    return 1;
+}
+
+// query and/or clear cell/vts change
+int mp_dvdnav_iscellchage(stream_t *stream, int clear) {
+    dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+    if (!priv->cell_change) return 0;
+    if (clear) priv->cell_change=0;
+    return 1;
+}
+
+// set/reset wait and auto mode wait (suspensed block read)
+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->wait_read=mode;
+    if (automode>=0) priv->wait_read_automode=automode;
+    return;
+}
+
+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);
+}
+
+int mp_dvdnav_get_logical_audio(stream_t *stream, int id) {
+    dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+    uint8_t audio_num = id;
+    return dvdnav_get_audio_logical_stream(priv->dvdnav,audio_num);
+}
+
+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);
+}
+
+int mp_dvdnav_is_audio_change(stream_t *stream) {
+    dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+    if(!priv->audio_change) return 0;
+    priv->audio_change=0;
+    return 1;
+}
+
+int mp_dvdnav_is_spu_change(stream_t *stream) {
+    dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+    if(!priv->spu_change) return 0;
+    priv->audio_change=0;
+    return 1;
+}
+
+int mp_dvdnav_is_change(stream_t *stream) {
+    int tit = 0, part = 0, tit_nr = 0, part_nr = 0;
+    dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+    if(!priv->stream_change) return 0;
+    priv->stream_change=0;
+    dvdnav_current_title_info(priv->dvdnav, &tit, &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;
+    priv->chapters_nr = part_nr;
+    priv->title=tit;
+    priv->part=part;
+    int i,sub_id;
+    uint16_t language;
+    priv->nr_of_subtitles=0;
+    priv->nr_of_channels=0;
+    if (!priv->vts_domain) return 1;
+    for(i=0;i<32;i++) {
+	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++) {
+	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);
+	priv->audio_streams[priv->nr_of_channels].language=language;
+	priv->audio_streams[priv->nr_of_channels].id=sub_id;
+	priv->audio_streams[priv->nr_of_channels].type=0;
+	priv->audio_streams[priv->nr_of_channels].channels=0;
+	priv->nr_of_channels++;
+	}
+    return 1;
+}
+
+
+void mp_dvdnav_set_audio_channels(stream_t *stream,demuxer_t *demuxer) {
+int i,res,id,nav_id, demux_id;
+dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+
+for(id=0;id<priv->nr_of_channels;id++) {
+    res=-1;
+    nav_id=mp_dvdnav_get_logical_audio(stream, id);
+    for(i=0;i<8;i++) {
+	demux_id=i;
+	if(demux_control(demuxer, DEMUXER_CTRL_GET_AUDIO, &demux_id)!=DEMUXER_CTRL_OK) continue;
+	if(demux_id==-1) continue;
+	if((demux_id & 0x0f)==(nav_id & 0x0f)) {res=demux_id; break;}
+	}
+    if(res!=-1) {
+	priv->audio_streams[id].id=res;
+	switch(res & 0xE0){  // 1110 0000 b  (high 3 bit: type  low 5: id)
+	    case 0x00: priv->audio_streams[id].type=2; break; // mpeg
+	    case 0xA0: priv->audio_streams[id].type=4; break;  // dvd pcm
+	    case 0x80: if((res & 0xF8) == 0x88) priv->audio_streams[id].type=6; //dts
+                  else priv->audio_streams[id].type=0; break; // ac3
+	    }
+	}
+    }
+}
+
+void mp_dvdnav_play_title(stream_t *stream, int title) {
+dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+
+dvdnav_title_play(priv->dvdnav, title);
+}
+
+void mp_dvdnav_play_chapter(stream_t *stream, int chapter) {
+dvdnav_priv_t * priv=(dvdnav_priv_t*)stream->priv;
+
+if(priv->title==0) return;
+dvdnav_part_play(priv->dvdnav, priv->title, chapter);
 }
 
 stream_info_t stream_info_dvdnav = {
--- libmpdemux/demuxer.c	 (revision 22492)
+++ libmpdemux/demuxer.c	 (working copy)
@@ -384,6 +384,7 @@
       }
       ds->pts_bytes+=p->len; // !!!
       if(p->stream_pts != MP_NOPTS_VALUE) demux->stream_pts=p->stream_pts;
+      if(p->stream_pts == MP_NOPTS_VALUE+1.0f) demux->stream_pts=MP_NOPTS_VALUE;
       ds->flags=p->flags;
       // unlink packet:
       ds->bytes-=p->len;
--- libmpdemux/demuxer.h	 (revision 22492)
+++ libmpdemux/demuxer.h	 (working copy)
@@ -80,6 +80,7 @@
 #define DEMUXER_CTRL_RESYNC 13
 #define DEMUXER_CTRL_SWITCH_VIDEO 14
 #define DEMUXER_CTRL_IDENTIFY_PROGRAM 15
+#define DEMUXER_CTRL_GET_AUDIO 16
 
 // Holds one packet/frame/whatever
 typedef struct demux_packet_st {
--- libmpdemux/demux_mpg.c	 (revision 22492)
+++ libmpdemux/demux_mpg.c	 (working copy)
@@ -1007,7 +1007,14 @@
             }
             *((int*)arg) = demuxer->audio->id;
             return DEMUXER_CTRL_OK;
-
+	case DEMUXER_CTRL_GET_AUDIO: {
+	    int stream_num,ret;
+	    stream_num=*((int*)arg);
+	    if(stream_num<0 || stream_num>mpg_d->num_a_streams) ret=-1; else
+        	ret=mpg_d->a_stream_ids[stream_num];
+            *((int*)arg) = ret;
+	    return DEMUXER_CTRL_OK;
+	    }
 	default:
 	    return DEMUXER_CTRL_NOTIMPL;
     }
--- input/input.c	 (revision 22492)
+++ input/input.c	 (working copy)
@@ -149,6 +149,8 @@
 
 #ifdef USE_DVDNAV
   { MP_CMD_DVDNAV, "dvdnav", 1, { {MP_CMD_ARG_INT,{0}}, {-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}} } },
 #endif
 
 #ifdef HAVE_MENU
--- input/input.h	 (revision 22492)
+++ input/input.h	 (working copy)
@@ -92,6 +92,8 @@
 #define MP_CMD_SET_MOUSE_POS 90
 #define MP_CMD_STEP_PROPERTY 91
 #define MP_CMD_RADIO_STEP_FREQ 92
+#define MP_CMD_SWITCH_TITLE 93
+#define MP_CMD_SWITCH_CHAPTER 94
 
 #define MP_CMD_GUI_EVENTS       5000
 #define MP_CMD_GUI_LOADFILE     5001
