summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/xine-engine/metronom.c88
-rw-r--r--src/xine-engine/video_out.c64
2 files changed, 96 insertions, 56 deletions
diff --git a/src/xine-engine/metronom.c b/src/xine-engine/metronom.c
index f1803e431..57c34698b 100644
--- a/src/xine-engine/metronom.c
+++ b/src/xine-engine/metronom.c
@@ -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.137 2004/04/09 15:06:02 mroi Exp $
+ * $Id: metronom.c,v 1.138 2004/04/22 23:19:03 tmattern Exp $
*/
#ifdef HAVE_CONFIG_H
@@ -39,7 +39,6 @@
#define LOG
#define LOG_AUDIO
*/
-
#define METRONOM_INTERNAL
#define METRONOM_CLOCK_INTERNAL
@@ -55,6 +54,10 @@
#define VIDEO_DRIFT_TOLERANCE 45000
#define AUDIO_DRIFT_TOLERANCE 45000
+/* metronom video modes */
+#define VIDEO_PREDICTION_MODE 0 /* use pts + frame duration */
+#define VIDEO_PTS_MODE 1 /* use only pts */
+
/* redefine abs as macro to handle 64-bit diffs.
i guess llabs may not be available everywhere */
#define abs(x) ( ((x)<0) ? -(x) : (x) )
@@ -456,20 +459,25 @@ static void metronom_got_video_frame (metronom_t *this, vo_frame_t *img) {
this->img_cpt++;
+ if (img->duration) {
+ this->video_mode = VIDEO_PREDICTION_MODE;
+ this->img_duration = img->duration;
+ } else {
+ /* will skip the whole predicted vpts stuff */
+ this->video_mode = VIDEO_PTS_MODE;
+ }
+
if (pts && pts != this->last_video_pts) {
- /*
- * Compute img duration if it's not provided by the decoder
- * example: mpeg streams with an invalid frame rate
- */
if (!img->duration) {
+ /* Compute the duration of previous frames using this formula:
+ * duration = (curent_pts - last_pts) / (frame count between the 2 pts)
+ * This duration will be used to predict the next frame vpts.
+ */
if (this->last_video_pts && this->img_cpt) {
this->img_duration = (pts - this->last_video_pts) / this->img_cpt;
lprintf("computed frame_duration = %" PRId64 "\n", this->img_duration );
}
- img->duration = this->img_duration;
- } else {
- this->img_duration = img->duration;
}
this->img_cpt = 0;
this->last_video_pts = pts;
@@ -484,49 +492,53 @@ static void metronom_got_video_frame (metronom_t *this, vo_frame_t *img) {
vpts = pts + this->vpts_offset;
- diff = this->video_vpts - vpts;
-
- lprintf("video diff is %" PRId64 " (predicted %" PRId64 ", given %" PRId64 ")\n", diff, this->video_vpts, vpts);
+ if (this->video_mode == VIDEO_PREDICTION_MODE) {
+
+ diff = this->video_vpts - vpts;
- if ((abs (diff) > VIDEO_DRIFT_TOLERANCE) || (this->force_video_jump)) {
- this->force_video_jump = 0;
- this->video_vpts = vpts;
- this->video_drift = 0;
+ lprintf("video diff is %" PRId64 " (predicted %" PRId64 ", given %" PRId64 ")\n", diff, this->video_vpts, vpts);
- xprintf(this->xine, XINE_VERBOSITY_DEBUG, "video jump\n");
- } else {
+ if ((abs (diff) > VIDEO_DRIFT_TOLERANCE) || (this->force_video_jump)) {
+ this->force_video_jump = 0;
+ this->video_vpts = vpts;
+ this->video_drift = 0;
- this->video_drift = diff;
- this->video_drift_step = diff / 30;
- /* this will fix video drift with a constant compensation each
- frame for about 1 second of video. */
+ xprintf(this->xine, XINE_VERBOSITY_DEBUG, "video jump\n");
- if (diff) lprintf("video drift, drift is %" PRId64 "\n", this->video_drift);
- }
- } else {
- if (!img->duration) {
- img->duration = this->img_duration;
+ } else {
+
+ this->video_drift = diff;
+ this->video_drift_step = diff / 30;
+ /* this will fix video drift with a constant compensation each
+ frame for about 1 second of video. */
+
+ if (diff) lprintf("video drift, drift is %" PRId64 "\n", this->video_drift);
+ }
} else {
- this->img_duration = img->duration;
+ /* VIDEO_PTS_MODE: do not use the predicted value */
+ this->video_vpts = vpts;
}
}
-
img->vpts = this->video_vpts + this->av_offset;
- lprintf("video vpts for %10lld : %10lld (duration:%d drift:%" PRId64 " step:%" PRId64 ")\n",
- pts, this->video_vpts, img->duration, this->video_drift, this->video_drift_step );
-
- if( this->video_drift * this->video_drift_step > 0 )
- {
- img->duration -= this->video_drift_step;
+ if (this->video_mode == VIDEO_PREDICTION_MODE) {
+ lprintf("video vpts for %10lld : %10lld (duration:%d drift:%" PRId64 " step:%" PRId64 ")\n",
+ pts, this->video_vpts, img->duration, this->video_drift, this->video_drift_step );
- this->video_drift -= this->video_drift_step;
+ if (this->video_drift * this->video_drift_step > 0) {
+ img->duration -= this->video_drift_step;
+ this->img_duration = img->duration;
+ this->video_drift -= this->video_drift_step;
+ }
}
-
- this->video_vpts += img->duration;
+ /* We need to update this->video_vpts is both modes.
+ * this->video_vpts is used as the next frame vpts if next frame pts=0
+ */
+ this->video_vpts += this->img_duration;
+
pthread_mutex_unlock (&this->lock);
}
diff --git a/src/xine-engine/video_out.c b/src/xine-engine/video_out.c
index 598b48830..65a7f7d56 100644
--- a/src/xine-engine/video_out.c
+++ b/src/xine-engine/video_out.c
@@ -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: video_out.c,v 1.189 2004/03/23 15:38:04 mroi Exp $
+ * $Id: video_out.c,v 1.190 2004/04/22 23:19:04 tmattern Exp $
*
* frame allocation / queuing / scheduling / output functions
*/
@@ -51,7 +51,9 @@
#include "metronom.h"
#include "xineutils.h"
-#define NUM_FRAME_BUFFERS 15
+#define NUM_FRAME_BUFFERS 15
+#define MAX_USEC_TO_SLEEP 20000
+#define DEFAULT_FRAME_DURATION 3000 /* 30 frames per second */
#define NULL_STREAM (xine_stream_t *)-1
@@ -373,9 +375,10 @@ static int vo_frame_draw (vo_frame_t *img, xine_stream_t *stream) {
this->num_frames_delivered++;
diff = pic_vpts - cur_vpts;
+
/* avoid division by zero */
if( img->duration <= 0 )
- img->duration = 3000;
+ img->duration = DEFAULT_FRAME_DURATION;
/* Frame dropping slow start:
* The engine starts to drop frames if there is less than frame_drop_limit
@@ -619,6 +622,7 @@ static void expire_frames (vos_t *this, int64_t cur_vpts) {
int64_t pts;
int64_t diff;
vo_frame_t *img;
+ int duration;
pthread_mutex_lock(&this->display_img_buf_queue->mutex);
@@ -629,8 +633,9 @@ static void expire_frames (vos_t *this, int64_t cur_vpts) {
*/
diff = 1000000; /* always enter the while-loop */
+ duration = 0;
- while (img && (diff > img->duration || this->discard_frames)) {
+ while (img) {
if (img->is_first) {
lprintf("expire_frames: first_frame !\n");
@@ -645,10 +650,18 @@ static void expire_frames (vos_t *this, int64_t cur_vpts) {
break;
}
+ if( !img->duration ) {
+ if( img->next )
+ duration = img->next->vpts - img->vpts;
+ else
+ duration = DEFAULT_FRAME_DURATION;
+ } else
+ duration = img->duration;
+
pts = img->vpts;
diff = cur_vpts - pts;
- if (diff > img->duration || this->discard_frames) {
+ if (diff > duration || this->discard_frames) {
if( !this->discard_frames ) {
xine_log(this->xine, XINE_LOG_MSG,
@@ -700,13 +713,19 @@ static void expire_frames (vos_t *this, int64_t cur_vpts) {
}
}
img = this->display_img_buf_queue->first;
- }
+
+ } else
+ break;
}
pthread_mutex_unlock(&this->display_img_buf_queue->mutex);
}
-static vo_frame_t *get_next_frame (vos_t *this, int64_t cur_vpts) {
+/* If it's not the time to display the next frame,
+ * the vpts of the next frame (if any) is returned, 0 otherwise.
+ */
+static vo_frame_t *get_next_frame (vos_t *this, int64_t cur_vpts,
+ int64_t *next_frame_vpts) {
vo_frame_t *img;
@@ -714,6 +733,8 @@ static vo_frame_t *get_next_frame (vos_t *this, int64_t cur_vpts) {
img = this->display_img_buf_queue->first;
+ *next_frame_vpts = 0;
+
/*
* still frame detection:
*/
@@ -764,6 +785,7 @@ static vo_frame_t *get_next_frame (vos_t *this, int64_t cur_vpts) {
lprintf ("diff %" PRId64 "\n", diff);
if (diff < 0) {
+ *next_frame_vpts = img->vpts;
pthread_mutex_unlock(&this->display_img_buf_queue->mutex);
return NULL;
}
@@ -933,7 +955,7 @@ static void *video_out_loop (void *this_gen) {
int64_t vpts, diff;
vo_frame_t *img;
vos_t *this = (vos_t *) this_gen;
- int64_t next_frame_vpts;
+ int64_t next_frame_vpts = 0;
int64_t usec_to_sleep;
#ifndef WIN32
@@ -950,8 +972,6 @@ static void *video_out_loop (void *this_gen) {
* of xine) : the video output loop
*/
- next_frame_vpts = this->clock->get_current_time (this->clock);
-
lprintf ("loop starting...\n");
while ( this->video_loop_running ) {
@@ -965,7 +985,8 @@ static void *video_out_loop (void *this_gen) {
lprintf ("loop iteration at %" PRId64 "\n", vpts);
expire_frames (this, vpts);
- img = get_next_frame (this, vpts);
+
+ img = get_next_frame (this, vpts, &next_frame_vpts);
/*
* if we have found a frame, display it
@@ -1015,13 +1036,10 @@ static void *video_out_loop (void *this_gen) {
/*
* wait until it's time to display next frame
*/
-
if (img) {
next_frame_vpts = img->vpts + img->duration;
- } else {
- /* we do not know, when the next frame is due, so only wait a little */
- next_frame_vpts += 1000;
}
+ /* else next_frame_vpts is returned by get_next_frame */
lprintf ("next_frame_vpts is %" PRId64 "\n", next_frame_vpts);
@@ -1031,7 +1049,17 @@ static void *video_out_loop (void *this_gen) {
if (this->clock->speed == XINE_SPEED_PAUSE)
paused_loop (this, vpts);
- usec_to_sleep = (next_frame_vpts - vpts) * 100 / 9;
+ if (next_frame_vpts) {
+ usec_to_sleep = (next_frame_vpts - vpts) * 100 / 9;
+ } else {
+ /* we don't know when the next frame is due, only wait a little */
+ usec_to_sleep = 1000;
+ next_frame_vpts = vpts; /* wait only once */
+ }
+
+ /* limit usec_to_sleep to maintain responsiveness */
+ if (usec_to_sleep > MAX_USEC_TO_SLEEP)
+ usec_to_sleep = MAX_USEC_TO_SLEEP;
lprintf ("%" PRId64 " usec to sleep at master vpts %" PRId64 "\n", usec_to_sleep, vpts);
@@ -1039,8 +1067,8 @@ static void *video_out_loop (void *this_gen) {
xprintf(this->xine, XINE_VERBOSITY_DEBUG,
"video_out: vpts/clock error, next_vpts=%" PRId64 " cur_vpts=%" PRId64 "\n", next_frame_vpts,vpts);
- if (usec_to_sleep>0)
- xine_usec_sleep (usec_to_sleep);
+ if (usec_to_sleep > 0)
+ xine_usec_sleep (usec_to_sleep);
} while ( (usec_to_sleep > 0) && this->video_loop_running);
}