[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