changeset 31972:96559880e475

Improve A/V sync when not using -correct-pts. This fixes at least playing PAFF streams with the native ts demuxer. (Breaks the non-standard -demuxer lavf -nocorrect-pts.) Patch by P«”sztor Szil«”rd, bartosteka freemail hu
author cehoyos
date Tue, 07 Sep 2010 16:20:52 +0000
parents 910579aafc61
children c2d29ae022a4
files libmpcodecs/dec_video.c libmpcodecs/dec_video.h mencoder.c mplayer.c
diffstat 4 files changed, 51 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/libmpcodecs/dec_video.c	Tue Sep 07 16:14:56 2010 +0000
+++ b/libmpcodecs/dec_video.c	Tue Sep 07 16:20:52 2010 +0000
@@ -388,7 +388,7 @@
 }
 
 void *decode_video(sh_video_t *sh_video, unsigned char *start, int in_size,
-                   int drop_frame, double pts)
+                   int drop_frame, double pts, int *full_frame)
 {
     mp_image_t *mpi = NULL;
     unsigned int t = GetTimer();
@@ -406,6 +406,9 @@
 	mpi = NULL;
     }
 
+    if (full_frame)
+	*full_frame = got_picture;
+
     delay = get_current_video_decoder_lag(sh_video);
     if (correct_pts && pts != MP_NOPTS_VALUE
         && (got_picture || sh_video->num_buffered_pts < delay)) {
--- a/libmpcodecs/dec_video.h	Tue Sep 07 16:14:56 2010 +0000
+++ b/libmpcodecs/dec_video.h	Tue Sep 07 16:20:52 2010 +0000
@@ -29,7 +29,7 @@
 int init_best_video_codec(sh_video_t *sh_video, char** video_codec_list, char** video_fm_list);
 void uninit_video(sh_video_t *sh_video);
 
-void *decode_video(sh_video_t *sh_video, unsigned char *start, int in_size, int drop_frame, double pts);
+void *decode_video(sh_video_t *sh_video, unsigned char *start, int in_size, int drop_frame, double pts, int *full_frame);
 int filter_video(sh_video_t *sh_video, void *frame, double pts);
 
 int get_video_quality_max(sh_video_t *sh_video);
--- a/mencoder.c	Tue Sep 07 16:14:56 2010 +0000
+++ b/mencoder.c	Tue Sep 07 16:20:52 2010 +0000
@@ -464,7 +464,7 @@
 
         if (vfilter) {
             int softskip = (vfilter->control(vfilter, VFCTRL_SKIP_NEXT_FRAME, 0) == CONTROL_TRUE);
-            void *decoded_frame = decode_video(sh_video, frame_data->start, frame_data->in_size, !softskip, MP_NOPTS_VALUE);
+            void *decoded_frame = decode_video(sh_video, frame_data->start, frame_data->in_size, !softskip, MP_NOPTS_VALUE, NULL);
 	    if (decoded_frame)
 		filter_video(sh_video, decoded_frame, MP_NOPTS_VALUE);
         }
@@ -1535,7 +1535,7 @@
                      (!sh_video->vfilter ||
                       ((vf_instance_t *)sh_video->vfilter)->control(sh_video->vfilter, VFCTRL_SKIP_NEXT_FRAME, 0) != CONTROL_TRUE);
     void *decoded_frame = decode_video(sh_video,frame_data.start,frame_data.in_size,
-                                       drop_frame, MP_NOPTS_VALUE);
+                                       drop_frame, MP_NOPTS_VALUE, NULL);
     blit_frame = decoded_frame && filter_video(sh_video, decoded_frame, MP_NOPTS_VALUE);}
 
     if (sh_video->vf_initialized < 0) mencoder_exit(1, NULL);
--- a/mplayer.c	Tue Sep 07 16:14:56 2010 +0000
+++ b/mplayer.c	Tue Sep 07 16:20:52 2010 +0000
@@ -1827,7 +1827,7 @@
 	if (in_size > max_framesize)
 	    max_framesize = in_size;
 	current_module = "decode video";
-	decoded_frame = decode_video(sh_video, start, in_size, drop_frame, pts);
+	decoded_frame = decode_video(sh_video, start, in_size, drop_frame, pts, NULL);
 	if (decoded_frame) {
 	    update_subtitles(sh_video, sh_video->pts, mpctx->d_sub, 0);
 	    update_teletext(sh_video, mpctx->demuxer, 0);
@@ -2381,7 +2381,9 @@
 	void *decoded_frame = NULL;
 	int drop_frame=0;
 	int in_size;
-
+	int full_frame;
+
+    do {
 	current_module = "video_read_frame";
 	frame_time = sh_video->next_frame_time;
 	in_size = video_read_frame(sh_video, &sh_video->next_frame_time,
@@ -2402,27 +2404,56 @@
 	    return -1;
 	if (in_size > max_framesize)
 	    max_framesize = in_size; // stats
-	sh_video->timer += frame_time;
-	if (mpctx->sh_audio)
-	    mpctx->delay -= frame_time;
-	// video_read_frame can change fps (e.g. for ASF video)
-	vo_fps = sh_video->fps;
 	drop_frame = check_framedrop(frame_time);
-	update_subtitles(sh_video, sh_video->pts, mpctx->d_sub, 0);
-	update_teletext(sh_video, mpctx->demuxer, 0);
-	update_osd_msg();
 	current_module = "decode_video";
 #ifdef CONFIG_DVDNAV
+	full_frame = 1;
 	decoded_frame = mp_dvdnav_restore_smpi(&in_size,&start,decoded_frame);
 	/// still frame has been reached, no need to decode
 	if (in_size > 0 && !decoded_frame)
 #endif
 	decoded_frame = decode_video(sh_video, start, in_size, drop_frame,
-				     sh_video->pts);
+				     sh_video->pts, &full_frame);
+
+    if (full_frame) {
+	sh_video->timer += frame_time;
+
+	// Time-based PTS recalculation.
+	// The key to maintaining A-V sync is to not touch PTS until the proper frame is reached
+	if (sh_video->pts != MP_NOPTS_VALUE) {
+	    if (sh_video->last_pts != MP_NOPTS_VALUE) {
+		double pts = sh_video->last_pts + frame_time;
+		double ptsdiff = fabs(pts - sh_video->pts);
+
+		// Allow starting PTS recalculation at the appropriate frame only
+		mpctx->framestep_found |= (ptsdiff <= frame_time * 1.5);
+
+		// replace PTS only if we're not too close and not too far
+		// and a correctly timed frame has been found, otherwise
+		// keep pts to eliminate rounding errors or catch up with stream
+		if (ptsdiff > frame_time * 20)
+		    mpctx->framestep_found = 0;
+		if (ptsdiff * 10 > frame_time && mpctx->framestep_found)
+		    sh_video->pts = pts;
+		else
+		    mp_dbg(MSGT_AVSYNC,MSGL_DBG2,"Keeping PTS at %6.2f\n", sh_video->pts);
+	    }
+	    sh_video->last_pts = sh_video->pts;
+	}
+	if (mpctx->sh_audio)
+	    mpctx->delay -= frame_time;
+	// video_read_frame can change fps (e.g. for ASF video)
+	vo_fps = sh_video->fps;
+	update_subtitles(sh_video, sh_video->pts, mpctx->d_sub, 0);
+	update_teletext(sh_video, mpctx->demuxer, 0);
+	update_osd_msg();
+    }
 #ifdef CONFIG_DVDNAV
 	/// save back last still frame for future display
 	mp_dvdnav_save_smpi(in_size,start,decoded_frame);
 #endif
+    } while (!full_frame);
+
 	current_module = "filter_video";
 	*blit_frame = (decoded_frame && filter_video(sh_video, decoded_frame,
 						    sh_video->pts));
@@ -2452,28 +2483,6 @@
 	frame_time = sh_video->pts - sh_video->last_pts;
 	sh_video->last_pts = sh_video->pts;
 	sh_video->timer += frame_time;
-	// Time-based PTS recalculation.
-	// The key to maintaining A-V sync is to not touch PTS until the proper frame is reached
-	if (sh_video->pts != MP_NOPTS_VALUE) {
-	    if (sh_video->last_pts != MP_NOPTS_VALUE) {
-		double pts = sh_video->last_pts + frame_time;
-		double ptsdiff = fabs(pts - sh_video->pts);
-
-		// Allow starting PTS recalculation at the appropriate frame only
-		mpctx->framestep_found |= (ptsdiff <= frame_time * 1.5);
-
-		// replace PTS only if we're not too close and not too far
-		// and a correctly timed frame has been found, otherwise
-		// keep pts to eliminate rounding errors or catch up with stream
-		if (ptsdiff > frame_time * 20)
-		    mpctx->framestep_found = 0;
-		if (ptsdiff * 10 > frame_time && mpctx->framestep_found)
-		    sh_video->pts = pts;
-		else
-		    mp_dbg(MSGT_AVSYNC,MSGL_DBG2,"Keeping PTS at %6.2f\n", sh_video->pts);
-	    }
-	    sh_video->last_pts = sh_video->pts;
-	}
 	if(mpctx->sh_audio)
 	    mpctx->delay -= frame_time;
 	*blit_frame = res > 0;
@@ -2662,6 +2671,7 @@
 	mpctx->num_buffered_frames = 0;
 	mpctx->delay = 0;
 	mpctx->time_frame = 0;
+	mpctx->framestep_found = 0;
 	// Not all demuxers set d_video->pts during seek, so this value
 	// (which is used by at least vobsub and edl code below) may
 	// be completely wrong (probably 0).
@@ -3711,6 +3721,7 @@
 int frame_time_remaining=0; // flag
 int blit_frame=0;
 mpctx->num_buffered_frames=0;
+mpctx->framestep_found=0;
 
 // Make sure old OSD does not stay around,
 // e.g. with -fixed-vo and same-resolution files