From 77bd595ad2ff339f46d63b15a9040e4b1a70b378 Mon Sep 17 00:00:00 2001 From: Marton Balint Date: Sat, 6 Oct 2012 23:55:29 +0200 Subject: [PATCH] ffplay: fix external time sync mode We now initalize the external clock to 0 and, we use the system clock to regulate the timings of audio and video in external clock sync mode. We recover from external clock sync loss, when the delay to external clock is bigger than AV_NOSYNC_THRESHOLD. Signed-off-by: Marton Balint --- ffplay.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/ffplay.c b/ffplay.c index 917883e34d..d9f751ca5a 100644 --- a/ffplay.c +++ b/ffplay.c @@ -153,8 +153,9 @@ typedef struct VideoState { int audio_stream; int av_sync_type; - double external_clock; /* external clock base */ - int64_t external_clock_time; + double external_clock; ///< external clock base + double external_clock_drift; ///< external clock base - time (av_gettime) at which we updated external_clock + int64_t external_clock_time; ///< last reference time double audio_clock; double audio_diff_cum; /* used for AV difference average computation */ @@ -1044,9 +1045,11 @@ static double get_video_clock(VideoState *is) /* get the current external clock value */ static double get_external_clock(VideoState *is) { - int64_t ti; - ti = av_gettime(); - return is->external_clock + ((ti - is->external_clock_time) * 1e-6); + if (is->paused) { + return is->external_clock; + } else { + return is->external_clock_drift + av_gettime() / 1000000.0; + } } /* get the current master clock value */ @@ -1070,6 +1073,19 @@ static double get_master_clock(VideoState *is) return val; } +static void update_external_clock_pts(VideoState *is, double pts) +{ + is->external_clock_time = av_gettime(); + is->external_clock = pts; + is->external_clock_drift = pts - is->external_clock_time / 1000000.0; +} + +static void check_external_clock_sync(VideoState *is, double pts) { + if (fabs(get_external_clock(is) - pts) > AV_NOSYNC_THRESHOLD) { + update_external_clock_pts(is, pts); + } +} + /* seek in the stream */ static void stream_seek(VideoState *is, int64_t pos, int64_t rel, int seek_by_bytes) { @@ -1093,6 +1109,7 @@ static void stream_toggle_pause(VideoState *is) } is->video_current_pts_drift = is->video_current_pts - av_gettime() / 1000000.0; } + update_external_clock_pts(is, get_external_clock(is)); is->paused = !is->paused; } @@ -1159,6 +1176,7 @@ static void update_video_pts(VideoState *is, double pts, int64_t pos) { is->video_current_pts_drift = is->video_current_pts - time; is->video_current_pos = pos; is->frame_last_pts = pts; + check_external_clock_sync(is, is->video_current_pts); } /* called to display each frame */ @@ -2116,6 +2134,7 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len) /* Let's assume the audio driver that is used by SDL has two periods. */ is->audio_current_pts = is->audio_clock - (double)(2 * is->audio_hw_buf_size + is->audio_write_buf_size) / bytes_per_sec; is->audio_current_pts_drift = is->audio_current_pts - audio_callback_time / 1000000.0; + check_external_clock_sync(is, is->audio_current_pts); } static int audio_open(void *opaque, int64_t wanted_channel_layout, int wanted_nb_channels, int wanted_sample_rate, struct AudioParams *audio_hw_params) @@ -2548,6 +2567,7 @@ static int read_thread(void *arg) packet_queue_put(&is->videoq, &flush_pkt); } } + update_external_clock_pts(is, (seek_target + ic->start_time) / (double)AV_TIME_BASE); is->seek_req = 0; eof = 0; } @@ -2677,6 +2697,7 @@ static VideoState *stream_open(const char *filename, AVInputFormat *iformat) is->continue_read_thread = SDL_CreateCond(); + update_external_clock_pts(is, 0.0); is->audio_current_pts_drift = -av_gettime() / 1000000.0; is->video_current_pts_drift = is->audio_current_pts_drift; is->av_sync_type = av_sync_type;