[MPlayer-dev-eng] [patch] A-V sync tuneup, round 2

PALLAI Roland dap at omnis.hu
Wed Nov 7 00:25:55 CET 2001


 hello!


 Mplayer currently do a simple A-V sync method, that's adjust the video
stream to the audio stream frame by frame, without any maximum correction
limit between two frames. It means if a video frame lates somehow, the
next frame will come (much) faster than the 'normal', cause it's try to
correct the video stream latency within 1 cycle.. Unfortunately, frames
are lating frequently because Intel's clocktick, so if you keep your eyes
open, you can see little jumps on slowly scrolling scenes in any HQ
movie.. if the correction is over +-20%, that's easily noticeable, I've
checked with my friends ;}


 this patch do the following things:
  - shows if latency between two frames is larger than frametime+20% or
	is smaller than frametime-20% (last two number in brackets)
  - implements soft-sleep for much precise sleep timing. it's eats up
	+~10% of CPU time, but _just_ the idle CPU time
  - do smooth A-V sync, doesn't allows 'unexpected' corrections over +-10%
	of frametime between two frames.  it's maybe sounds scary, but 10%
	is enough for A-V sync


test results (Dungeons and Dragons.avi; 640x352 at 24fps, DivX):

original version:
... 23% 24%  2.4% 0 49% [0|235<>267]
Exiting... (Requested number of frames played)
real	0m42.411s
user	0m16.470s
sys	0m0.400s

patched version:
... 23% 24%  2.4% 0 49% [0|5<>5]
Exiting... (Requested number of frames played)
real	0m42.413s
user	0m16.610s
sys	0m0.430s


ps# Arpi, it contains some bugfixes and improvements since previous
	version, IMHO it's much cleaner and stable



sorry for my poor english, bye,
--
  DaP

-------------- next part --------------
diff -urN -x configure -x config.h.in -x aclocal.m4 -x *~ -x *.P -x stamp-h -x stamp-h.in -x config.cache -x config.log -x config.status -x config.h -x Makefile -x POTFILES -x .depend -x config.mak -x version.h -x mplayer.txt -x .#* -x CVS -x loader main/cfg-mplayer.h main-dev/cfg-mplayer.h
--- main/cfg-mplayer.h	Tue Oct 23 22:15:00 2001
+++ main-dev/cfg-mplayer.h	Sat Nov  3 15:37:37 2001
@@ -290,5 +290,6 @@
 	{"-help", help_text, CONF_TYPE_PRINT, CONF_NOCFG, 0, 0},
 	{"help", help_text, CONF_TYPE_PRINT, CONF_NOCFG, 0, 0},
 	{"h", help_text, CONF_TYPE_PRINT, CONF_NOCFG, 0, 0},
+	{"nodapsync", &nodapsync, CONF_TYPE_FLAG, 0, 0, 1},
 	{NULL, NULL, 0, 0, 0, 0}
 };
diff -urN -x configure -x config.h.in -x aclocal.m4 -x *~ -x *.P -x stamp-h -x stamp-h.in -x config.cache -x config.log -x config.status -x config.h -x Makefile -x POTFILES -x .depend -x config.mak -x version.h -x mplayer.txt -x .#* -x CVS -x loader main/mplayer.c main-dev/mplayer.c
--- main/mplayer.c	Mon Oct 29 00:38:52 2001
+++ main-dev/mplayer.c	Tue Nov  6 22:46:31 2001
@@ -79,6 +79,8 @@
 void find_sub(subtitle* subtitles,int key);
 #endif
 
+int nodapsync = 0;
+
 //**************************************************************************//
 //             Config file
 //**************************************************************************//
@@ -1126,12 +1128,15 @@
 char osd_text_buffer[64];
 int drop_frame=0;
 int drop_frame_cnt=0;
+int too_slow_frame_cnt=0;
+int too_fast_frame_cnt=0;
 // for auto-quality:
 float AV_delay=0; // average of A-V timestamp differences
 double cvideo_base_vtime;
 double cvideo_base_vframe;
 double vdecode_time;
-
+unsigned int lastframeout_ts;
+float frame_time_corr_avg=0;
 
 //================ SETUP AUDIO ==========================
   current_module="setup_audio";
@@ -1367,7 +1372,7 @@
     // Increase video timers:
     sh_video->num_frames+=frame_time;
     ++sh_video->num_frames_decoded;
-    frame_time*=sh_video->frametime;
+    frame_time*=sh_video->frametime;	/* CHECKME: if mpeg2 { ft != 1 } */
     if(demuxer->file_format==DEMUXER_TYPE_ASF && !force_fps){
         // .ASF files has no fixed FPS - just frame durations!
         float d=d_video->pts-pts1;
@@ -1418,29 +1423,70 @@
       // It's time to sleep...
       current_module="sleep";
 
-      time_frame-=GetRelativeTime(); // reset timer
+      time_frame-=GetRelativeTime(); // reset timer -- for nosound
 
       if(sh_audio && !d_audio->eof){
+    	  float i;
           int delay=audio_out->get_delay();
           mp_dbg(MSGT_AVSYNC,MSGL_DBG2,"delay=%d\n",delay);
-          time_frame=sh_video->timer;
-          time_frame-=sh_audio->timer-(float)delay/(float)sh_audio->o_bps;
-          // we are out of time... drop next frame!
-	  if(time_frame<-2*frame_time){
-	      static int drop_message=0;
-	      drop_frame=frame_dropping; // tricky!
-	      ++drop_frame_cnt;
-	      if(drop_frame_cnt>50 && AV_delay>0.5 && !drop_message){
-	          drop_message=1;
-	          mp_msg(MSGT_AVSYNC,MSGL_WARN,MSGTR_SystemTooSlow);
-	      }
-	      mp_msg(MSGT_AVSYNC,MSGL_DBG2,"\nframe drop %d, %.2f\n", drop_frame, time_frame);
-	  }
-      } else {
-          if( (time_frame<-3*frame_time || time_frame>3*frame_time) || benchmark)
-	      time_frame=0;
-	  
-      }
+	  if (nodapsync) {
+	      /* old AV-sync */
+              time_frame=sh_video->timer;
+              time_frame-=sh_audio->timer-(float)delay/(float)sh_audio->o_bps;
+	      if (time_frame < -2 * frame_time) {
+	          static int drop_message=0;
+	          drop_frame=frame_dropping; // tricky!
+	          ++drop_frame_cnt;
+	          if(drop_frame_cnt>50 && AV_delay>0.5 && !drop_message){
+	              drop_message=1;
+	              mp_msg(MSGT_AVSYNC,MSGL_WARN,MSGTR_SystemTooSlow);
+	          }
+	          printf ("WARNING (nodapsync): A-V SYNC FAILED: FRAMEDROP!\n");
+	          mp_msg(MSGT_AVSYNC,MSGL_DBG2,"\nframe drop %d, %.2f\n", drop_frame, time_frame);
+	      } else {
+    		  if( (time_frame<-3*frame_time || time_frame>3*frame_time) || benchmark)
+	    	      time_frame=0;
+    	      }
+	  } else {
+	      /* SH-AV-sync */
+	      /* i = sh_video->timer - (sh_audio->timer - (float)((float)delay + sh_audio->a_buffer_len) / (float)sh_audio->o_bps); */
+	      i = sh_video->timer - (sh_audio->timer - (float)((float)delay) / (float)sh_audio->o_bps);
+	      // printf ("audio slp req: %.3f TF: %.3f delta: %.3f (v: %.3f a: %.3f) | ", i, time_frame,
+	      //	    i - time_frame, sh_video->timer, sh_audio->timer - (float)((float)delay / (float)sh_audio->o_bps));
+	      if(i<-2*frame_time){
+		  static int drop_message=0;
+	          drop_frame=frame_dropping; // tricky!
+	          ++drop_frame_cnt;
+		  if(drop_frame_cnt>50 && AV_delay>0.5 && !drop_message){
+	    	      drop_message=1;
+	    	      mp_msg(MSGT_AVSYNC,MSGL_WARN,MSGTR_SystemTooSlow);
+	         }
+		printf ("WARNING: A-V SYNC FAILED: FRAMEDROP (i=%.3f)!\n", i);
+	        mp_msg(MSGT_AVSYNC,MSGL_DBG2,"\nframe drop %d, %.2f\n", drop_frame, time_frame);
+	        /* go into unlimited-TF cycle */
+	      } else {
+#define	SL_CORR_AVG_LEN	125
+	        /* don't adjust under framedropping */
+	        frame_time_corr_avg = (frame_time_corr_avg * (SL_CORR_AVG_LEN - 1) +
+	    				(i - time_frame)) / SL_CORR_AVG_LEN;
+#define	UNEXP_CORR_MAX	0.1
+#define	UNEXP_CORR_WARN	1.0
+	        time_frame += frame_time_corr_avg;
+	        // printf ("{%.3f - %.3f}\n", i - time_frame, frame_time + frame_time_corr_avg);
+	        if (i - time_frame < (frame_time + frame_time_corr_avg) * UNEXP_CORR_MAX &&
+		    i - time_frame > (frame_time + frame_time_corr_avg) * -UNEXP_CORR_MAX)
+		    time_frame = i;
+	        else {
+		    if (i - time_frame > (frame_time + frame_time_corr_avg) * UNEXP_CORR_WARN ||
+		        i - time_frame < (frame_time + frame_time_corr_avg) * -UNEXP_CORR_WARN)
+		        printf ("WARNING: A-V SYNC LAG TOO LARGE: %.3f {%.3f - %.3f} (too little UNEXP_CORR_MAX?)\n",
+		  	    i - time_frame, i, time_frame);
+		        time_frame += (frame_time + frame_time_corr_avg) * ((i > time_frame) ?
+		    		      UNEXP_CORR_MAX : -UNEXP_CORR_MAX);
+	        }
+	      }	/* /start dropframe */
+      }	/* /sh_audio */
+    }	/* /end dropframe */
 
 //      if(verbose>1)printf("sleep: %5.3f  a:%6.3f  v:%6.3f  \n",time_frame,sh_audio->timer,sh_video->timer);
 
@@ -1452,27 +1498,70 @@
       }
 #endif
       
-      while(time_frame>0.005){
-          if(time_frame<=0.020)
-//             usec_sleep(10000); // sleeps 1 clock tick (10ms)!
-             usec_sleep(0); // sleeps 1 clock tick (10ms)!
-          else
-             usec_sleep(1000000*(time_frame-0.002));
+#define	SL_MAX_LAG	0.003	/* maximum sleep latency (-3ms) */
+      if (nodapsync) {
+#if 0	/* soft-sleep */
+        while(time_frame>0.000){
+            if (!(time_frame < 0.010 - SL_MAX_LAG))
+                usec_sleep(0);	/* man nanosleep (2001) */
+#else
+        while(time_frame>0.005){
+            if(time_frame<=0.010)
+                usec_sleep(0); // sleeps 1 clock tick (10ms)!
+            else
+                usec_sleep(1000000*(time_frame-0.002));
+#endif
 #ifdef HAVE_NEW_GUI
-          if(use_gui){
-            EventHandling();
-          }
+            if(use_gui){
+        	EventHandling();
+            }
 #endif
-          time_frame-=GetRelativeTime();
-      }
+            time_frame-=GetRelativeTime();
+	}
+      } else {
+        if (time_frame < -SL_MAX_LAG)
+	    printf ("WARNING: frame decoding was too slow - no sleep (%.3f)!\n", time_frame);
+        while (time_frame > 0.000) {
+//printf ("TF1: %.3f\n", time_frame);
+#if 1	/* soft-sleep, need more powerful CPU, but gives much better V linearity */
+    	    if (time_frame > 0.010 - SL_MAX_LAG)
+#endif
+        	usec_sleep(0);	/* man nanosleep (2001) */
+#ifdef HAVE_NEW_GUI
+    	    if(use_gui){
+        	EventHandling();
+    	    }
+#endif
+    	    time_frame-=GetRelativeTime();
+//printf ("TF2: %.3f\n", time_frame);
+        }
+        if (time_frame >= 0.001) {
+	    printf ("PANIC: too short sleep: %.3f\n", time_frame);
+	    time_frame = 0;
+	}
+        if (time_frame < -SL_MAX_LAG) {
+	    printf ("NOTICE: too long sleep: %.3f\n", time_frame);
+	    time_frame = -SL_MAX_LAG;	/* may cause too_slow_cnt++ */
+        }
+      } /* /nodapsync */
 
         current_module="flip_page";
 #ifdef USE_LIBVO2
         if(blit_frame) vo2_flip(video_out,0);
 #else
 	video_out->check_events();
-        if(blit_frame){
+        if(blit_frame){	/* doesn't run under framedrop */
 	   unsigned int t2=GetTimer();
+	   float j;
+#define	FRAME_LAG_WARN	0.2
+	   j = ((float)t2 - lastframeout_ts) / 1000000;
+	   lastframeout_ts = GetTimer();
+	   if (j < frame_time + frame_time * -FRAME_LAG_WARN)
+		too_fast_frame_cnt++;
+		/* printf ("PANIC: too fast frame (%.3f)!\n", j); */
+	   else if (j > frame_time + frame_time * FRAME_LAG_WARN)
+		too_slow_frame_cnt++;
+		/* printf ("PANIC: too slow frame (%.3f)!\n", j); */
 	   video_out->flip_page();
 	   t2=GetTimer()-t2;vout_time_usage+=t2*0.000001f;
 	}
@@ -1541,16 +1630,21 @@
           max_pts_correction=default_max_pts_correction;
         else
           max_pts_correction=sh_video->frametime*0.10; // +-10% of time
-        sh_audio->timer+=x; c_total+=x;
-        if(!quiet) mp_msg(MSGT_AVSYNC,MSGL_STATUS,"A:%6.1f V:%6.1f A-V:%7.3f ct:%7.3f  %3d/%3d  %2d%% %2d%% %4.1f%% %d %d %d%%\r",
-	  a_pts-audio_delay-delay,v_pts,AV_delay,c_total,
-          (int)sh_video->num_frames,(int)sh_video->num_frames_decoded,
-          (sh_video->timer>0.5)?(int)(100.0*video_time_usage/(double)sh_video->timer):0,
-          (sh_video->timer>0.5)?(int)(100.0*vout_time_usage/(double)sh_video->timer):0,
-          (sh_video->timer>0.5)?(100.0*audio_time_usage/(double)sh_video->timer):0
+        sh_audio->timer+=x;
+	c_total+=x;
+        if(!quiet) mp_msg(MSGT_AVSYNC,MSGL_STATUS,"A:%6.1f V:%6.1f A-V:%7.3f ct:%7.3f %3d %2d%% %2d%% %4.1f%% %d %d%% [%d|%d<>%d]\r",
+ 	  a_pts-audio_delay-delay,v_pts,AV_delay,c_total
+          ,(int)sh_video->num_frames
+//	  ,(int)sh_video->num_frames_decoded
+          ,(sh_video->timer>0.5)?(int)(100.0*video_time_usage/(double)sh_video->timer):0
+          ,(sh_video->timer>0.5)?(int)(100.0*vout_time_usage/(double)sh_video->timer):0
+          ,(sh_video->timer>0.5)?(100.0*audio_time_usage/(double)sh_video->timer):0
+ 	  ,output_quality
+ 	  ,cache_fill_status
+//	  ,frame_time_corr_avg
           ,drop_frame_cnt
-	  ,output_quality
-	  ,cache_fill_status
+	  ,too_slow_frame_cnt
+	  ,too_fast_frame_cnt
         );
         fflush(stdout);
       }
@@ -1648,6 +1742,7 @@
              if(use_stdin) usec_sleep(1000); // do not eat the CPU
          }
          osd_function=OSD_PLAY;
+         (void)GetRelativeTime();	// keep TF around FT in next cycle
       if (audio_out && sh_audio)
         audio_out->resume();	// resume audio
 #ifdef HAVE_NEW_GUI
@@ -1916,6 +2011,8 @@
       osd_visible=sh_video->fps; // to rewert to PLAY pointer after 1 sec
       audio_time_usage=0; video_time_usage=0; vout_time_usage=0;
       drop_frame_cnt=0;
+      too_slow_frame_cnt=0;
+      too_fast_frame_cnt=0;
   
   }
   rel_seek_secs=0;


More information about the MPlayer-dev-eng mailing list