summaryrefslogtreecommitdiff
path: root/src/xine-engine/metronom.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xine-engine/metronom.c')
-rw-r--r--src/xine-engine/metronom.c346
1 files changed, 86 insertions, 260 deletions
diff --git a/src/xine-engine/metronom.c b/src/xine-engine/metronom.c
index b578ea5cf..e54bbca1c 100644
--- a/src/xine-engine/metronom.c
+++ b/src/xine-engine/metronom.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2000-2002 the xine project
*
- * This file is part of xine, a unix video player.
+ * This file is part of xine, a free video player.
*
* xine is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: metronom.c,v 1.64 2002/03/10 21:16:15 miguelfreitas Exp $
+ * $Id: metronom.c,v 1.65 2002/03/11 12:31:26 guenter Exp $
*/
#ifdef HAVE_CONFIG_H
@@ -253,7 +253,7 @@ static void metronom_set_audio_rate (metronom_t *this, int64_t pts_per_smpls) {
}
static int64_t metronom_got_spu_packet (metronom_t *this, int64_t pts,
- int64_t duration, int64_t scr ) {
+ int64_t duration) {
int64_t vpts;
pthread_mutex_lock (&this->lock);
@@ -265,47 +265,30 @@ static int64_t metronom_got_spu_packet (metronom_t *this, int64_t pts,
this->spu_vpts=this->spu_vpts;
}
- /*
- It happens with the dxr3 that got_spu_packet is called before
- got_video_frame. Since video_wrap_offset is zero until then,
- the return value would be wrong. In this case zero is returned.
-
- Also this->video_discontinuity means that scr discontinuity was
- detected but this->video_wrap_offset not updated (would give
- wrong values too).
- */
- if ( this->video_discontinuity ) {
- /* we can safely use audio_wrap_offset if already updated */
- if( !this->audio_discontinuity ) {
- vpts = pts + this->audio_wrap_offset;
- } else {
- vpts = 0;
- }
- } else {
- vpts = pts + this->video_wrap_offset;
+ if ( !this->in_discontinuity ) {
+ vpts = pts + this->vpts_offset;
+ } else {
+ vpts = 0;
}
pthread_mutex_unlock (&this->lock);
return vpts;
}
-static void metronom_expect_video_discontinuity (metronom_t *this, int starting) {
+static void metronom_handle_video_discontinuity (metronom_t *this, int is_stream_start,
+ int64_t disc_off) {
pthread_mutex_lock (&this->lock);
- this->video_starting = starting;
-
- this->video_discontinuity = 10;
-
this->video_discontinuity_count++;
pthread_cond_signal (&this->video_discontinuity_reached);
printf ("metronom: video discontinuity #%d\n",
this->video_discontinuity_count);
- if( this->have_audio ) {
- while ( this->audio_discontinuity_count <
- this->video_discontinuity_count ) {
+ if (this->have_audio) {
+ while (this->audio_discontinuity_count <
+ this->video_discontinuity_count) {
printf ("metronom: waiting for audio discontinuity #%d\n",
this->video_discontinuity_count);
@@ -313,145 +296,89 @@ static void metronom_expect_video_discontinuity (metronom_t *this, int starting)
pthread_cond_wait (&this->audio_discontinuity_reached, &this->lock);
}
- if ( this->video_vpts < this->audio_vpts ) {
+ if (this->video_vpts < this->audio_vpts) {
this->video_vpts = this->audio_vpts;
printf ("metronom: video vpts adjusted to %lld\n", this->video_vpts);
}
}
-
+
+ if (this->in_discontinuity)
+ this->vpts_offset = this->next_vpts_offset;
+
+ if (is_stream_start) {
+ this->vpts_offset = this->video_vpts;
+ } else {
+ this->next_vpts_offset = this->vpts_offset - disc_off;
+ this->in_discontinuity = 30;
+ }
pthread_mutex_unlock (&this->lock);
}
+static void metronom_video_stream_start (metronom_t *this) {
+ metronom_handle_video_discontinuity (this, 1, 0);
+}
+
+static void metronom_expect_video_discontinuity (metronom_t *this, int64_t disc_off) {
+ metronom_handle_video_discontinuity (this, 0, disc_off);
+}
+
static void metronom_got_video_frame (metronom_t *this, vo_frame_t *img) {
int64_t vpts;
int64_t pts = img->pts;
int64_t duration = img->duration;
- int pts_discontinuity = 0;
pthread_mutex_lock (&this->lock);
-
- /* check for pts discontinuities against the predicted pts value */
- if (pts && this->last_video_pts) {
-
- int64_t diff, predicted_pts;
-
- predicted_pts = this->last_video_pts + duration;
-
- diff = pts - predicted_pts;
-
-#ifdef LOG
- printf ("metronom: got video pts %lld, predicted %lld (= %lld + %lld) => diff %lld\n",
- pts, predicted_pts, this->last_video_pts, duration, diff);
-#endif
-
- if ( abs (diff) > WRAP_THRESHOLD ) {
- pts_discontinuity = 1;
-
-#ifdef LOG
- printf ("metronom: this is a video discontinuity\n");
-#endif
+ if (this->in_discontinuity) {
+ this->in_discontinuity--;
- /*
- * ignore discontinuities created by frame reordering around
- * the REAL discontinuity. :)
- */
- if( !this->video_discontinuity ) {
- pts = 0;
-#ifdef LOG
- printf ("metronom: not expecting a video discontinuity => ignored\n");
-#endif
- }
- }
+ if (!this->in_discontinuity)
+ this->vpts_offset = this->next_vpts_offset;
+ else
+ pts = 0; /* ignore pts during discontinuities */
}
if (pts) {
+ int64_t diff;
+
/*
- * check if there was any pending SCR discontinuity (video_discontinuity
- * is set from the decoder loop) together with pts discont.
+ * compare predicted (this->video_vpts) and given (pts+vpts_offset)
+ * pts values - hopefully they will be the same
+ * if not, for small diffs try to interpolate
+ * for big diffs: jump
*/
- if ( this->video_discontinuity &&
- (pts_discontinuity || this->video_starting) ) {
- this->video_starting = 0;
- this->video_discontinuity = 0;
- this->wrap_diff_counter = 0;
-
- this->video_wrap_offset = this->video_vpts - pts;
-
- vpts = pts + this->video_wrap_offset;
-
- printf ("metronom: video pts discontinuity/start, pts is %lld, wrap_offset is %lld, vpts is %lld\n",
- pts, this->video_wrap_offset, vpts);
-
- } else {
-
- int64_t diff;
-
- /*
- * audio and video wrap are not allowed to differ for too long
- */
-
- if ( this->have_audio
- && (this->video_wrap_offset != this->audio_wrap_offset) ){
+
+ vpts = pts + this->vpts_offset;
- this->wrap_diff_counter++;
-
- if (this->wrap_diff_counter > MAX_NUM_WRAP_DIFF) {
-
- printf ("metronom: forcing video_wrap (%lld) and audio wrap (%lld)",
- this->video_wrap_offset, this->audio_wrap_offset);
-
- if (this->video_wrap_offset > this->audio_wrap_offset)
- this->audio_wrap_offset = this->video_wrap_offset;
- else
- this->video_wrap_offset = this->audio_wrap_offset;
-
- printf (" to %lld\n", this->video_wrap_offset);
-
- this->wrap_diff_counter = 0;
- }
- }
-
- /*
- * compare predicted (this->video_vpts) and given (pts+wrap_offset)
- * pts values - hopefully they will be the same
- * if not, for small diffs try to interpolate
- * for big diffs: jump
- */
-
- vpts = pts + this->video_wrap_offset;
-
- diff = this->video_vpts - vpts;
+ diff = this->video_vpts - vpts;
#ifdef LOG
- printf ("metronom: video diff is %lld (predicted %lld, given %lld)\n",
- diff, this->video_vpts, vpts);
+ printf ("metronom: video diff is %lld (predicted %lld, given %lld)\n",
+ diff, this->video_vpts, vpts);
#endif
- if (abs (diff) > VIDEO_DRIFT_TOLERANCE) {
+ if (abs (diff) > VIDEO_DRIFT_TOLERANCE) {
- this->video_vpts = vpts;
- this->video_drift = 0;
+ this->video_vpts = vpts;
+ this->video_drift = 0;
#ifdef LOG
- printf ("metronom: video jump, ignoring predicted vpts\n");
+ printf ("metronom: video jump\n");
#endif
- } else if (diff) {
+ } else if (diff) {
- this->video_drift = diff / 30;
+ this->video_drift = diff;
#ifdef LOG
- printf ("metronom: video drift, compensation will be %lld pts/frame\n",
- this->video_drift);
+ printf ("metronom: video drift, drift is %lld\n", this->video_drift);
#endif
- }
}
-
- this->last_video_pts = pts;
- } else
- this->last_video_pts = this->video_vpts - this->video_wrap_offset;
+ }
+
+ this->video_vpts -= this->video_drift / 30;
+ this->video_drift -= this->video_drift / 30;
img->vpts = this->video_vpts + this->av_offset;
@@ -459,18 +386,16 @@ static void metronom_got_video_frame (metronom_t *this, vo_frame_t *img) {
printf ("metronom: video vpts for %10lld : %10lld (duration:%lld)\n",
pts, this->video_vpts, duration);
#endif
-
- this->video_vpts += duration - this->video_drift;
- img->duration -= this->video_drift;
+
+ this->video_vpts += duration;
pthread_mutex_unlock (&this->lock);
}
-static void metronom_expect_audio_discontinuity (metronom_t *this) {
+static void metronom_expect_audio_discontinuity (metronom_t *this, int64_t disc_off) {
pthread_mutex_lock (&this->lock);
- this->audio_discontinuity = 10;
this->audio_discontinuity_count++;
pthread_cond_signal (&this->audio_discontinuity_reached);
@@ -487,120 +412,40 @@ static void metronom_expect_audio_discontinuity (metronom_t *this) {
}
if ( this->audio_vpts < this->video_vpts ) {
- this->audio_vpts = this->video_vpts;
+ this->audio_vpts = this->video_vpts;
printf ("metronom: audio vpts adjusted to %lld\n", this->audio_vpts);
}
-
- /* this->num_audio_samples_guessed = 1; */
- /* this->last_audio_pts = this->audio_vpts - this->audio_wrap_offset; */
+
+ /* next_vpts_offset, in_discontinuity is handled in expect_video_discontinuity */
pthread_mutex_unlock (&this->lock);
}
+static void metronom_audio_stream_start (metronom_t *this) {
+ metronom_expect_audio_discontinuity (this, 0);
+}
static int64_t metronom_got_audio_samples (metronom_t *this, int64_t pts,
- int nsamples, int64_t scr) {
+ int nsamples) {
int64_t vpts;
#ifdef LOG
- printf ("metronom: got %d audio samples, pts is %lld, last_pts is %lld, diff = %lld\n",
- nsamples, pts, this->last_audio_pts, pts - this->last_audio_pts);
- printf ("metronom: audio wrap offset is %lld\n", this->audio_wrap_offset);
+ printf ("metronom: got %d audio samples, pts is %lld\n", nsamples, pts);
#endif
pthread_mutex_lock (&this->lock);
-#if 0
- if (this->audio_discontinuity && this->video_discontinuity) {
-
- /* this is needed to take care of still frame with no audio
- were vpts are not updated.
- we can only do it here because audio and video decoder threads
- have just been synced */
- if ( this->audio_vpts < metronom_get_current_time(this) ) {
- this->audio_vpts = metronom_get_current_time(this) + PREBUFFER_PTS_OFFSET;
- this->video_vpts = this->audio_vpts;
- printf ("metronom: audio/video vpts too old, adjusted to %lld\n",
- this->audio_vpts);
- }
- }
-#endif
-
+ if (this->in_discontinuity)
+ pts = 0; /* ignore pts during discontinuities */
+
if (pts) {
-
- /*
- * discontinuity ?
- */
- if ( this->audio_discontinuity ) {
- this->audio_discontinuity = 0;
- this->wrap_diff_counter = 0;
-
- this->audio_wrap_offset = this->audio_vpts - pts ;
-
- /*
- * this->num_audio_samples_guessed
- * (this->audio_pts_delta + this->pts_per_smpls) / AUDIO_SAMPLE_NUM ;
- */
-
- vpts = pts + this->audio_wrap_offset;
-
- printf ("metronom: audio pts discontinuity/start, pts is %lld, wrap_offset is %lld, vpts is %lld\n",
- pts, this->audio_wrap_offset, vpts);
-
-
- } else {
-
- /*
- * audio and video wrap are not allowed to differ
- * for too long
- */
-
- if ( this->video_wrap_offset != this->audio_wrap_offset ) {
- this->wrap_diff_counter++;
-
- if (this->wrap_diff_counter > MAX_NUM_WRAP_DIFF) {
-
- printf ("metronom: forcing video_wrap (%lld) and audio wrap (%lld)",
- this->video_wrap_offset, this->audio_wrap_offset);
-
- if (this->video_wrap_offset > this->audio_wrap_offset)
- this->audio_wrap_offset = this->video_wrap_offset;
- else
- this->video_wrap_offset = this->audio_wrap_offset;
-
- printf ("to %lld\n", this->video_wrap_offset);
-
- this->wrap_diff_counter = 0;
- }
- }
-
- vpts = pts + this->audio_wrap_offset;
-
- /*
- * calc delta to compensate wrong samplerates
- */
-
- if (this->last_audio_pts && (pts>this->last_audio_pts)) {
- int32_t vpts_diff;
-
- vpts_diff = vpts - this->audio_vpts;
-
- this->audio_pts_delta += vpts_diff*AUDIO_SAMPLE_NUM / (this->num_audio_samples_guessed);
-
- if (abs(this->audio_pts_delta) >= MAX_AUDIO_DELTA)
- this->audio_pts_delta = 0;
- }
- }
-
- this->num_audio_samples_guessed = 0;
- this->last_audio_pts = pts;
- this->audio_vpts = vpts;
+ vpts = pts + this->vpts_offset;
+ this->audio_vpts = vpts;
} else
vpts = this->audio_vpts;
- this->audio_vpts += nsamples * (this->audio_pts_delta + this->pts_per_smpls) / AUDIO_SAMPLE_NUM;
- this->num_audio_samples_guessed += nsamples;
+ this->audio_vpts += nsamples * this->pts_per_smpls / AUDIO_SAMPLE_NUM;
#ifdef LOG
printf ("metronom: audio vpts for %10lld : %10lld\n", pts, vpts);
@@ -734,6 +579,8 @@ metronom_t * metronom_init (int have_audio, void *xine) {
this->got_video_frame = metronom_got_video_frame;
this->got_audio_samples = metronom_got_audio_samples;
this->got_spu_packet = metronom_got_spu_packet;
+ this->audio_stream_start = metronom_audio_stream_start;
+ this->video_stream_start = metronom_video_stream_start;
this->expect_audio_discontinuity = metronom_expect_audio_discontinuity;
this->expect_video_discontinuity = metronom_expect_video_discontinuity;
this->set_av_offset = metronom_set_av_offset;
@@ -759,47 +606,26 @@ metronom_t * metronom_init (int have_audio, void *xine) {
printf ("metronom: cannot create sync thread (%s)\n",
strerror(err));
- pthread_cond_init (&this->video_discontinuity_reached, NULL);
- pthread_cond_init (&this->audio_discontinuity_reached, NULL);
-
- this->av_offset = 0;
-
+ this->av_offset = 0;
+ this->in_discontinuity = 0;
+ this->vpts_offset = 0;
+ this->next_vpts_offset = 0;
/* initialize video stuff */
- this->have_audio = have_audio;
this->video_vpts = PREBUFFER_PTS_OFFSET;
-
- this->last_video_pts = 0;
this->video_drift = 0;
-
- this->video_wrap_offset = PREBUFFER_PTS_OFFSET;
- this->wrap_diff_counter = 0;
-
- this->video_discontinuity = 0;
this->video_discontinuity_count = 0;
+ pthread_cond_init (&this->video_discontinuity_reached, NULL);
/* initialize audio stuff */
+ this->have_audio = have_audio;
this->audio_vpts = PREBUFFER_PTS_OFFSET;
-
- this->audio_pts_delta = 0;
-
- this->num_audio_samples_guessed = 1;
- this->last_audio_pts = 0;
-
- this->audio_wrap_offset = PREBUFFER_PTS_OFFSET;
- this->wrap_diff_counter = 0;
-
- this->audio_discontinuity = 0;
this->audio_discontinuity_count = 0;
+ pthread_cond_init (&this->audio_discontinuity_reached, NULL);
+
return this;
}
-
-
-
-
-
-