# HG changeset patch # User corey # Date 1287644730 0 # Node ID acb796d7ca50a9f15bd25cf15c4a7c250e2b1745 # Parent 520d72f61c8c0bf74ecd1f1e3502b61f023d719b 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. diff -r 520d72f61c8c -r acb796d7ca50 mencoder.c --- a/mencoder.c Wed Oct 20 08:12:40 2010 +0000 +++ b/mencoder.c Thu Oct 21 07:05:30 2010 +0000 @@ -354,15 +354,28 @@ 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 @@ } 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 @@ 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 @@ if(sh_audio){ // get audio: - while(mux_a->timer-audio_preloadtimer){ + while(a_muxer_time-audio_preloadtimer; + tottime -= a_muxer_time; if (tottime > 1./audio_density) tottime = 1./audio_density; } else tottime = 1./audio_density; @@ -1359,7 +1377,7 @@ 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(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 @@ 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 @@ 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(!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 @@ 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