[MPlayer-cvslog] r32520 - trunk/mencoder.c

corey subversion at mplayerhq.hu
Thu Oct 21 09:05:30 CEST 2010


Author: corey
Date: Thu Oct 21 09:05:30 2010
New Revision: 32520

Log:
Make mencoder account for encoder delay when considering the current
time position of a muxer stream. To mencoder core, delayed frames
should be considered as "dealt with", since they'll get to the muxer
eventually. Without this compensation, mencoder will sometimes make
different frame skip/duplicate decisions on the first of a two-pass
x264 encode (since x264 buffers many more frames on the first pass),
leading to a segfault in x264 when it gets fed more frames on the
second pass.

Modified:
   trunk/mencoder.c

Modified: trunk/mencoder.c
==============================================================================
--- trunk/mencoder.c	Wed Oct 20 10:12:40 2010	(r32519)
+++ trunk/mencoder.c	Thu Oct 21 09:05:30 2010	(r32520)
@@ -354,15 +354,28 @@ static void add_subtitles(char *filename
     subdata = subd;
 }
 
+/* Provide a timer value suitable for use in A/V sync calculations.
+ * mux->timer records the current position of the muxer stream.
+ * mux->encoder_delay is how many frames are currently buffered by the
+ * encoder. To mencoder core, encoder-buffered frames have been "dealt with"--
+ * they'll get to the muxer eventually. So, for the purposes of A/V sync,
+ * we need to add the total time length of buffered frames to the muxer stream
+ * position. */
+static double adjusted_muxer_time(muxer_stream_t *mux)
+{
+    if (! mux) return MP_NOPTS_VALUE;
+    return mux->timer + (double) mux->encoder_delay * mux->h.dwScale/mux->h.dwRate;
+}
+
 /* This function returns the absolute time for which MEncoder will switch files
  * or move in the file so audio can be cut correctly. -1 if there is no limit. */
 static float stop_time(demuxer_t* demuxer, muxer_stream_t* mux_v)
 {
 	float timeleft = -1;
-	if (play_n_frames >= 0) timeleft = mux_v->timer + play_n_frames * (double)(mux_v->h.dwScale) / mux_v->h.dwRate;
+	if (play_n_frames >= 0) timeleft = adjusted_muxer_time(mux_v) + play_n_frames * (double)(mux_v->h.dwScale) / mux_v->h.dwRate;
 	if (end_at.type == END_AT_TIME && (timeleft > end_at.pos || timeleft == -1)) timeleft = end_at.pos;
 	if (next_edl_record && demuxer && demuxer->video) { // everything is OK to be checked
-		float tmp = mux_v->timer + next_edl_record->start_sec - demuxer->video->pts;
+		float tmp = adjusted_muxer_time(mux_v) + next_edl_record->start_sec - demuxer->video->pts;
 		if (timeleft == -1 || timeleft > tmp) {
 			// There's less time in EDL than what we already know
 			if (next_edl_record->action == EDL_SKIP && edl_seeking) {
@@ -1225,7 +1238,7 @@ if(file_format == DEMUXER_TYPE_TV)
 	}
 
 play_n_frames=play_n_frames_mf;
-if (curfile && end_at.type == END_AT_TIME) end_at.pos += mux_v->timer;
+if (curfile && end_at.type == END_AT_TIME) end_at.pos += adjusted_muxer_time(mux_v);
 
 if (edl_records) free_edl(edl_records);
 next_edl_record = edl_records = NULL;
@@ -1243,9 +1256,14 @@ while(!at_eof){
     float a_pts=0;
     float v_pts=0;
     int skip_flag=0; // 1=skip  -1=duplicate
+    double a_muxer_time;
+    double v_muxer_time;
+
+    a_muxer_time = adjusted_muxer_time(mux_a);
+    v_muxer_time = adjusted_muxer_time(mux_v);
 
     if((end_at.type == END_AT_SIZE && end_at.pos <= stream_tell(muxer->stream))  ||
-       (end_at.type == END_AT_TIME && end_at.pos < mux_v->timer))
+       (end_at.type == END_AT_TIME && end_at.pos < v_muxer_time))
         break;
 
     if(play_n_frames>=0){
@@ -1299,7 +1317,7 @@ goto_redo_edl:
 
 if(sh_audio){
     // get audio:
-    while(mux_a->timer-audio_preload<mux_v->timer){
+    while(a_muxer_time-audio_preload<v_muxer_time){
         float tottime;
 	int len=0;
 
@@ -1308,7 +1326,7 @@ if(sh_audio){
 	// or until the end of video:
 	tottime = stop_time(demuxer, mux_v);
 	if (tottime != -1) {
-		tottime -= mux_a->timer;
+		tottime -= a_muxer_time;
 		if (tottime > 1./audio_density) tottime = 1./audio_density;
 	}
 	else tottime = 1./audio_density;
@@ -1359,7 +1377,7 @@ if(sh_audio){
 				mux_a->buffer_len += len;
 			}
 	    }
-	    if (mux_v->timer == 0) mux_a->h.dwInitialFrames++;
+	    if (v_muxer_time == 0) mux_a->h.dwInitialFrames++;
 	}
 	else {
 	if(mux_a->h.dwSampleSize){
@@ -1382,8 +1400,9 @@ if(sh_audio){
 	}
 	if(len<=0) break; // EOF?
 	muxer_write_chunk(mux_a,len,AVIIF_KEYFRAME, MP_NOPTS_VALUE, MP_NOPTS_VALUE);
-	if(!mux_a->h.dwSampleSize && mux_a->timer>0)
-	    mux_a->wf->nAvgBytesPerSec=0.5f+(double)mux_a->size/mux_a->timer; // avg bps (VBR)
+	a_muxer_time = adjusted_muxer_time(mux_a); // update after muxing
+	if(!mux_a->h.dwSampleSize && a_muxer_time>0)
+	    mux_a->wf->nAvgBytesPerSec=0.5f+(double)mux_a->size/a_muxer_time; // avg bps (VBR)
 	if(mux_a->buffer_len>=len){
 	    mux_a->buffer_len-=len;
 	    fast_memcpy(mux_a->buffer,mux_a->buffer+len,mux_a->buffer_len);
@@ -1478,6 +1497,7 @@ default:
     void *decoded_frame = decode_video(sh_video,frame_data.start,frame_data.in_size,
                                        drop_frame, MP_NOPTS_VALUE, NULL);
     blit_frame = decoded_frame && filter_video(sh_video, decoded_frame, MP_NOPTS_VALUE);}
+    v_muxer_time = adjusted_muxer_time(mux_v); // update after muxing
 
     if (sh_video->vf_initialized < 0) mencoder_exit(1, NULL);
 
@@ -1550,10 +1570,7 @@ if(sh_audio && !demuxer2){
     AV_delay=(a_pts-v_pts);
     AV_delay-=audio_delay;
     AV_delay /= playback_speed;
-    AV_delay-=mux_a->timer-(mux_v->timer-(v_timer_corr+v_pts_corr));
-    // adjust for encoder delays
-    AV_delay -= (float) mux_a->encoder_delay * mux_a->h.dwScale/mux_a->h.dwRate;
-    AV_delay += (float) mux_v->encoder_delay * mux_v->h.dwScale/mux_v->h.dwRate;
+    AV_delay-=a_muxer_time-(v_muxer_time-(v_timer_corr+v_pts_corr));
 	// compensate input video timer by av:
         x=AV_delay*0.1f;
         if(x<-max_pts_correction) x=-max_pts_correction; else
@@ -1581,25 +1598,25 @@ if(sh_audio && !demuxer2){
       if(!quiet) {
 	if( mp_msg_test(MSGT_STATUSLINE,MSGL_V) ) {
 		mp_msg(MSGT_STATUSLINE,MSGL_STATUS,"Pos:%6.1fs %6df (%2d%%) %3dfps Trem:%4dmin %3dmb  A-V:%5.3f [%d:%d] A/Vms %d/%d D/B/S %d/%d/%d \r",
-	    	mux_v->timer, decoded_frameno, (int)(p*100),
+	    	v_muxer_time, decoded_frameno, (int)(p*100),
 	    	(t>1) ? (int)(decoded_frameno/t+0.5) : 0,
 	    	(p>0.001) ? (int)((t/p-t)/60) : 0,
 	    	(p>0.001) ? (int)(stream_tell(muxer->stream)/p/1024/1024) : 0,
 	    	v_pts_corr,
-	    	(mux_v->timer>1) ? (int)(mux_v->size/mux_v->timer/125) : 0,
-	    	(mux_a && mux_a->timer>1) ? (int)(mux_a->size/mux_a->timer/125) : 0,
+	    	(v_muxer_time>1) ? (int)(mux_v->size/v_muxer_time/125) : 0,
+	    	(mux_a && a_muxer_time>1) ? (int)(mux_a->size/a_muxer_time/125) : 0,
 			audiorate/audiosamples, videorate/videosamples,
 			duplicatedframes, badframes, skippedframes
 		);
 	} else
 	mp_msg(MSGT_STATUSLINE,MSGL_STATUS,"Pos:%6.1fs %6df (%2d%%) %5.2ffps Trem:%4dmin %3dmb  A-V:%5.3f [%d:%d]\r",
-	    mux_v->timer, decoded_frameno, (int)(p*100),
+	    v_muxer_time, decoded_frameno, (int)(p*100),
 	    (t>1) ? (float)(decoded_frameno/t) : 0,
 	    (p>0.001) ? (int)((t/p-t)/60) : 0,
 	    (p>0.001) ? (int)(stream_tell(muxer->stream)/p/1024/1024) : 0,
 	    v_pts_corr,
-	    (mux_v->timer>1) ? (int)(mux_v->size/mux_v->timer/125) : 0,
-	    (mux_a && mux_a->timer>1) ? (int)(mux_a->size/mux_a->timer/125) : 0
+	    (v_muxer_time>1) ? (int)(mux_v->size/v_muxer_time/125) : 0,
+	    (mux_a && a_muxer_time>1) ? (int)(mux_a->size/a_muxer_time/125) : 0
 	);
       }
     }
@@ -1612,7 +1629,7 @@ if(sh_audio && !demuxer2){
      int len;
      while((len=ds_get_packet_sub(d_dvdsub,&packet, NULL, NULL))>0){
 	 mp_msg(MSGT_MENCODER,MSGL_V,"\rDVD sub: len=%d  v_pts=%5.3f  s_pts=%5.3f  \n",len,sh_video->pts,d_dvdsub->pts);
-	     vobsub_out_output(vobsub_writer,packet,len,mux_v->timer + d_dvdsub->pts - sh_video->pts);
+	     vobsub_out_output(vobsub_writer,packet,len,v_muxer_time + d_dvdsub->pts - sh_video->pts);
      }
  }
  else


More information about the MPlayer-cvslog mailing list