summaryrefslogtreecommitdiffstats
path: root/mplayer.c
diff options
context:
space:
mode:
authorUoti Urpala <uau@glyph.nonexistent.invalid>2008-12-08 20:04:08 +0200
committerUoti Urpala <uau@glyph.nonexistent.invalid>2009-01-14 02:06:13 +0200
commit321c93ee998266cff4ce5b5eff2aaba4e2311dd0 (patch)
treeaa457dd522f75e384902e54e3d71e4f93071237e /mplayer.c
parent5204fda1213f1bb876fd71f16f44767edc8eae46 (diff)
downloadmpv-321c93ee998266cff4ce5b5eff2aaba4e2311dd0.tar.bz2
mpv-321c93ee998266cff4ce5b5eff2aaba4e2311dd0.tar.xz
core: Rewrite some of the A/V sync related code
Notable functionality changes: * Timing change between any two frames is now accurately limited to 1/10 of their nominal distance. Previous code did not always use the correct duration. * The status line now keeps showing the same A-V sync value from one video frame change to the next. Previously it kept recalculating the value using a new audio position but the same video position when the status line was updated between video frames. This incorrectly showed the video losing sync with audio. * The status line now displays actual measured A-V difference in autosync mode too. The previous code displayed values that completely ignored real timing in autosync mode, showing 0 A-V difference even when video was significantly behind audio due to inadequate decoding speed. The new behavior can make the shown A-V values appear more unstable if the audio out has unreliable delay measurements (the most likely reason to use autosync), but this is a display change rather than a timing quality change. * Autosync mode now tries to adjust timing by the amount of time vo_flip() calls take, so the calls start earlier and finish at the time the frame should be shown. Previously non-autosync mode adjusted for this but autosync did not. * The warning about the system being too slow to decode the video in realtime is now displayed in autosync mode too.
Diffstat (limited to 'mplayer.c')
-rw-r--r--mplayer.c151
1 files changed, 69 insertions, 82 deletions
diff --git a/mplayer.c b/mplayer.c
index 36e6c5d5f8..cc83c9e83c 100644
--- a/mplayer.c
+++ b/mplayer.c
@@ -4,6 +4,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <stdbool.h>
#include "config.h"
#include "talloc.h"
@@ -259,8 +260,6 @@ static char *stream_dump_name="stream.dump";
// A-V sync:
static float default_max_pts_correction=-1;//0.01f;
-static float max_pts_correction=0;//default_max_pts_correction;
-static float c_total=0;
float audio_delay=0;
static int ignore_start=0;
@@ -1160,16 +1159,25 @@ static void sadd_hhmmssf(char *buf, unsigned *pos, int len, float time) {
saddf(buf, pos, len, "%02d.%1d", ss, f1);
}
-/**
- * \brief print the status line
- * \param a_pos audio position
- * \param a_v A-V desynchronization
- * \param corr amount out A-V synchronization
- */
-static void print_status(struct MPContext *mpctx, float a_pos, float a_v, float corr)
+static void print_status(struct MPContext *mpctx, double a_pos, bool at_frame)
{
struct MPOpts *opts = &mpctx->opts;
sh_video_t * const sh_video = mpctx->sh_video;
+
+ if (mpctx->sh_audio && a_pos == MP_NOPTS_VALUE)
+ a_pos = playing_audio_pts(mpctx);
+ if (mpctx->sh_audio && sh_video && at_frame) {
+ mpctx->last_av_difference = a_pos - sh_video->pts - audio_delay;
+ if (mpctx->last_av_difference > 0.5 && drop_frame_cnt > 50
+ && !mpctx->drop_message_shown) {
+ mp_msg(MSGT_AVSYNC,MSGL_WARN,MSGTR_SystemTooSlow);
+ mpctx->drop_message_shown = true;
+ }
+ }
+ if (quiet)
+ return;
+
+
int width;
char *line;
unsigned pos = 0;
@@ -1204,7 +1212,8 @@ static void print_status(struct MPContext *mpctx, float a_pos, float a_v, float
// A-V sync
if (mpctx->sh_audio && sh_video)
- saddf(line, &pos, width, "A-V:%7.3f ct:%7.3f ", a_v, corr);
+ saddf(line, &pos, width, "A-V:%7.3f ct:%7.3f ",
+ mpctx->last_av_difference, mpctx->total_avsync_change);
// Video stats
if (sh_video)
@@ -1696,7 +1705,8 @@ static int check_framedrop(struct MPContext *mpctx, double frame_time) {
++total_frame_cnt;
// we should avoid dropping too many frames in sequence unless we
// are too late. and we allow 100ms A-V delay here:
- if (d < -dropped_frames*frame_time-0.100 && !mpctx->paused) {
+ if (d < -dropped_frames*frame_time-0.100 && !mpctx->paused
+ && !mpctx->update_video_immediately) {
++drop_frame_cnt;
++dropped_frames;
return frame_dropping;
@@ -1921,71 +1931,39 @@ static void mp_dvdnav_save_smpi(struct MPContext *mpctx, int in_size,
}
#endif /* CONFIG_DVDNAV */
-static void adjust_sync_and_print_status(struct MPContext *mpctx,
- int between_frames,
- float timing_error)
+/* Modify video timing to match the audio timeline. There are two main
+ * reasons this is needed. First, video and audio can start from different
+ * positions at beginning of file or after a seek (MPlayer starts both
+ * immediately even if they have different pts). Second, the file can have
+ * audio timestamps that are inconsistent with the duration of the audio
+ * packets, for example two consecutive timestamp values differing by
+ * one second but only a packet with enough samples for half a second
+ * of playback between them.
+ */
+static void adjust_sync(struct MPContext *mpctx, double frame_time)
{
struct MPOpts *opts = &mpctx->opts;
- current_module="av_sync";
-
- if(mpctx->sh_audio){
- double a_pts, v_pts;
-
- if (autosync)
- /*
- * If autosync is enabled, the value for delay must be calculated
- * a bit differently. It is set only to the difference between
- * the audio and video timers. Any attempt to include the real
- * or corrected delay causes the pts_correction code below to
- * try to correct for the changes in delay which autosync is
- * trying to measure. This keeps the two from competing, but still
- * allows the code to correct for PTS drift *only*. (Using a delay
- * value here, even a "corrected" one, would be incompatible with
- * autosync mode.)
- */
- a_pts = written_audio_pts(mpctx) - mpctx->delay;
- else
- a_pts = playing_audio_pts(mpctx);
+ current_module = "av_sync";
- v_pts = mpctx->sh_video->pts;
+ if (!mpctx->sh_audio)
+ return;
- {
- static int drop_message=0;
- double AV_delay = a_pts - audio_delay - v_pts;
- double x;
- if (AV_delay>0.5 && drop_frame_cnt>50 && drop_message==0){
- ++drop_message;
- mp_msg(MSGT_AVSYNC,MSGL_WARN,MSGTR_SystemTooSlow);
- }
- if (autosync)
- x = AV_delay*0.1f;
- else
- /* Do not correct target time for the next frame if this frame
- * was late not because of wrong target time but because the
- * target time could not be met */
- x = (AV_delay + timing_error * opts->playback_speed) * 0.1f;
- if (x < -max_pts_correction)
- x = -max_pts_correction;
- else if (x> max_pts_correction)
- x = max_pts_correction;
- if (default_max_pts_correction >= 0)
- max_pts_correction = default_max_pts_correction;
- else
- max_pts_correction = mpctx->sh_video->frametime*0.10; // +-10% of time
- if (!between_frames) {
- mpctx->delay+=x;
- c_total+=x;
- }
- if(!quiet)
- print_status(mpctx, a_pts - audio_delay, AV_delay, c_total);
- }
-
- } else {
- // No audio:
-
- if (!quiet)
- print_status(mpctx, 0, 0, 0);
- }
+ double a_pts = written_audio_pts(mpctx) - mpctx->delay;
+ double v_pts = mpctx->sh_video->pts;
+ double av_delay = a_pts - v_pts;
+ // Try to sync vo_flip() so it will *finish* at given time
+ av_delay += mpctx->last_vo_flip_duration;
+ av_delay -= audio_delay; // This much pts difference is desired
+
+ double change = av_delay * 0.1;
+ double max_change = default_max_pts_correction >= 0 ?
+ default_max_pts_correction : frame_time * 0.1;
+ if (change < -max_change)
+ change = -max_change;
+ else if (change > max_change)
+ change = max_change;
+ mpctx->delay += change;
+ mpctx->total_avsync_change += change;
}
static int fill_audio_out_buffers(struct MPContext *mpctx)
@@ -2522,6 +2500,7 @@ static int seek(MPContext *mpctx, double amount, int style)
mpctx->num_buffered_frames = 0;
mpctx->delay = 0;
mpctx->time_frame = 0;
+ mpctx->update_video_immediately = true;
// 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).
@@ -2544,8 +2523,7 @@ static int seek(MPContext *mpctx, double amount, int style)
edl_seek_reset(mpctx);
- c_total = 0;
- max_pts_correction = 0.1;
+ mpctx->total_avsync_change = 0;
audio_time_usage = 0; video_time_usage = 0; vout_time_usage = 0;
drop_frame_cnt = 0;
@@ -3733,6 +3711,9 @@ if (mpctx->stream->type == STREAMTYPE_DVDNAV) {
get_relative_time(mpctx); // reset current delta
mpctx->time_frame = 0;
+ mpctx->drop_message_shown = 0;
+ mpctx->update_video_immediately = true;
+ mpctx->total_avsync_change = 0;
while(!mpctx->stop_play){
float aq_sleep_time=0;
@@ -3763,11 +3744,10 @@ if(!mpctx->sh_video) {
double a_pos=0;
// sh_audio can be NULL due to video stream switching
// TODO: handle this better
- if(!quiet || end_at.type == END_AT_TIME && mpctx->sh_audio)
+ if (mpctx->sh_audio)
a_pos = playing_audio_pts(mpctx);
- if(!quiet)
- print_status(mpctx, a_pos, 0, 0);
+ print_status(mpctx, a_pos, false);
if(end_at.type == END_AT_TIME && end_at.pos < a_pos)
mpctx->stop_play = PT_NEXT_ENTRY;
@@ -3795,7 +3775,13 @@ if(!mpctx->sh_video) {
else {
// might return with !eof && !blit_frame if !correct_pts
mpctx->num_buffered_frames += blit_frame;
- mpctx->time_frame += frame_time / opts->playback_speed; // for nosound
+ if (mpctx->update_video_immediately) {
+ // Show this frame immediately, rest normally
+ mpctx->update_video_immediately = false;
+ } else {
+ mpctx->time_frame += frame_time / opts->playback_speed;
+ adjust_sync(mpctx, frame_time);
+ }
}
}
@@ -3837,11 +3823,12 @@ if(!mpctx->sh_video) {
vo_flip_page(mpctx->video_out);
mpctx->num_buffered_frames--;
- vout_time_usage += (GetTimer() - t2) * 0.000001;
+ mpctx->last_vo_flip_duration = (GetTimer() - t2) * 0.000001;
+ vout_time_usage += mpctx->last_vo_flip_duration;
+ print_status(mpctx, MP_NOPTS_VALUE, true);
}
-//====================== A-V TIMESTAMP CORRECTION: =========================
-
- adjust_sync_and_print_status(mpctx, frame_time_remaining, mpctx->time_frame);
+ else
+ print_status(mpctx, MP_NOPTS_VALUE, false);
//============================ Auto QUALITY ============================