diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/xine-engine/metronom.c | 88 | ||||
-rw-r--r-- | src/xine-engine/video_out.c | 64 |
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); } |