@ -98,9 +98,9 @@ typedef struct PacketQueue {
typedef struct VideoPicture {
double pts ; ///<presentation time stamp for this picture
double target_clock ; ///<av_gettime() time at which this should be displayed ideally
double duration ; ///<expected duration of the frame
int64_t pos ; ///<byte position in file
int skip ;
SDL_Overlay * bmp ;
int width , height ; /* source height & width */
int allocated ;
@ -197,7 +197,7 @@ typedef struct VideoState {
double frame_timer ;
double frame_last_pts ;
double frame_last_delay ;
double frame_last_duration ;
double video_clock ; ///<pts of last decoded frame / predicted pts of next decoded frame
int video_stream ;
AVStream * video_st ;
@ -1071,19 +1071,9 @@ static void stream_toggle_pause(VideoState *is)
is - > paused = ! is - > paused ;
}
static double compute_target_time ( double frame_current_pts , VideoState * is )
static double compute_target_delay ( double delay , VideoState * is )
{
double delay , sync_threshold , diff ;
/* compute nominal delay */
delay = frame_current_pts - is - > frame_last_pts ;
if ( delay < = 0 | | delay > = 10.0 ) {
/* if incorrect delay, use previous one */
delay = is - > frame_last_delay ;
} else {
is - > frame_last_delay = delay ;
}
is - > frame_last_pts = frame_current_pts ;
double sync_threshold , diff ;
/* update delay to follow master synchronisation source */
if ( ( ( is - > av_sync_type = = AV_SYNC_AUDIO_MASTER & & is - > audio_st ) | |
@ -1103,12 +1093,22 @@ static double compute_target_time(double frame_current_pts, VideoState *is)
delay = 2 * delay ;
}
}
is - > frame_timer + = delay ;
av_dlog ( NULL , " video: delay=%0.3f pts=%0.3f A-V=%f \n " ,
delay , frame_current_pts , - diff ) ;
av_dlog ( NULL , " video: delay=%0.3f A-V=%f \n " ,
delay , - diff ) ;
return is - > frame_timer ;
return delay ;
}
static void pictq_next_picture ( VideoState * is ) {
/* update queue size and signal for next picture */
if ( + + is - > pictq_rindex = = VIDEO_PICTURE_QUEUE_SIZE )
is - > pictq_rindex = 0 ;
SDL_LockMutex ( is - > pictq_mutex ) ;
is - > pictq_size - - ;
SDL_CondSignal ( is - > pictq_cond ) ;
SDL_UnlockMutex ( is - > pictq_mutex ) ;
}
/* called to display each frame */
@ -1125,34 +1125,45 @@ retry:
//nothing to do, no picture to display in the que
} else {
double time = av_gettime ( ) / 1000000.0 ;
double next_target ;
double last_duration , duration , delay ;
/* dequeue the picture */
vp = & is - > pictq [ is - > pictq_rindex ] ;
if ( time < vp - > target_clock )
if ( vp - > skip ) {
pictq_next_picture ( is ) ;
goto retry ;
}
/* compute nominal last_duration */
last_duration = vp - > pts - is - > frame_last_pts ;
if ( last_duration > 0 & & last_duration < 10.0 ) {
/* if duration of the last frame was sane, update last_duration in video state */
is - > frame_last_duration = last_duration ;
}
delay = compute_target_delay ( is - > frame_last_duration , is ) ;
if ( time < is - > frame_timer + delay )
return ;
is - > frame_last_pts = vp - > pts ;
is - > frame_timer + = delay ;
/* update current video pts */
is - > video_current_pts = vp - > pts ;
is - > video_current_pts_drift = is - > video_current_pts - time ;
is - > video_current_pos = vp - > pos ;
if ( is - > pictq_size > 1 ) {
VideoPicture * nextvp = & is - > pictq [ ( is - > pictq_rindex + 1 ) % VIDEO_PICTURE_QUEUE_SIZE ] ;
assert ( nextvp - > target_clock > = vp - > target_clock ) ;
next_target = nextvp - > target_clock ;
} else {
next_target = vp - > target_clock + vp - > duration ;
if ( is - > pictq_size > 1 ) {
VideoPicture * nextvp = & is - > pictq [ ( is - > pictq_rindex + 1 ) % VIDEO_PICTURE_QUEUE_SIZE ] ;
duration = nextvp - > pts - vp - > pts ; // More accurate this way, 1/time_base is often not reflecting FPS
} else {
duration = vp - > duration ;
}
if ( ( framedrop > 0 | | ( framedrop & & is - > audio_st ) ) & & time > next_target ) {
if ( ( framedrop > 0 | | ( framedrop & & is - > audio_st ) ) & & time > is - > frame_timer + duration ) {
is - > skip_frames * = 1.0 + FRAME_SKIP_FACTOR ;
if ( is - > pictq_size > 1 ) {
/* update queue size and signal for next picture */
if ( + + is - > pictq_rindex = = VIDEO_PICTURE_QUEUE_SIZE )
is - > pictq_rindex = 0 ;
SDL_LockMutex ( is - > pictq_mutex ) ;
is - > pictq_size - - ;
SDL_CondSignal ( is - > pictq_cond ) ;
SDL_UnlockMutex ( is - > pictq_mutex ) ;
pictq_next_picture ( is ) ;
goto retry ;
}
}
@ -1205,14 +1216,7 @@ retry:
if ( ! display_disable )
video_display ( is ) ;
/* update queue size and signal for next picture */
if ( + + is - > pictq_rindex = = VIDEO_PICTURE_QUEUE_SIZE )
is - > pictq_rindex = 0 ;
SDL_LockMutex ( is - > pictq_mutex ) ;
is - > pictq_size - - ;
SDL_CondSignal ( is - > pictq_cond ) ;
SDL_UnlockMutex ( is - > pictq_mutex ) ;
pictq_next_picture ( is ) ;
}
} else if ( is - > audio_st ) {
/* draw the next audio frame */
@ -1425,13 +1429,12 @@ static int queue_picture(VideoState *is, AVFrame *src_frame, double pts1, int64_
vp - > pts = pts ;
vp - > pos = pos ;
vp - > skip = 0 ;
/* now we can update the picture count */
if ( + + is - > pictq_windex = = VIDEO_PICTURE_QUEUE_SIZE )
is - > pictq_windex = 0 ;
SDL_LockMutex ( is - > pictq_mutex ) ;
vp - > target_clock = compute_target_time ( vp - > pts , is ) ;
is - > pictq_size + + ;
SDL_UnlockMutex ( is - > pictq_mutex ) ;
}
@ -1451,7 +1454,7 @@ static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacke
SDL_LockMutex ( is - > pictq_mutex ) ;
//Make sure there are no long delay timers (ideally we should just flush the que but thats harder)
for ( i = 0 ; i < VIDEO_PICTURE_QUEUE_SIZE ; i + + ) {
is - > pictq [ i ] . target_clock = 0 ;
is - > pictq [ i ] . skip = 1 ;
}
while ( is - > pictq_size & & ! is - > videoq . abort_request ) {
SDL_CondWait ( is - > pictq_cond , is - > pictq_mutex ) ;
@ -1460,7 +1463,7 @@ static int get_video_frame(VideoState *is, AVFrame *frame, int64_t *pts, AVPacke
SDL_UnlockMutex ( is - > pictq_mutex ) ;
is - > frame_last_pts = AV_NOPTS_VALUE ;
is - > frame_last_delay = 0 ;
is - > frame_last_duration = 0 ;
is - > frame_timer = ( double ) av_gettime ( ) / 1000000.0 ;
is - > skip_frames = 1 ;
is - > skip_frames_index = 0 ;