From 4f15163a94c863e3e0cf8a65f3ad6f88946f7670 Mon Sep 17 00:00:00 2001 From: Michael Roitzsch Date: Tue, 29 Oct 2002 16:02:43 +0000 Subject: engine improvements - output fifo flushing - more sophisticated discontinuity handling - seek improvement by waiting for at least one frame CVS patchset: 3089 CVS date: 2002/10/29 16:02:43 --- src/xine-engine/audio_decoder.c | 4 +- src/xine-engine/audio_out.c | 105 ++++++++++++++++-------- src/xine-engine/audio_out.h | 10 ++- src/xine-engine/demux.c | 8 ++ src/xine-engine/metronom.c | 173 ++++++++++++++++++++++++---------------- src/xine-engine/metronom.h | 14 ++-- src/xine-engine/video_decoder.c | 10 ++- src/xine-engine/video_out.c | 61 ++++++++++++-- src/xine-engine/video_out.h | 5 +- src/xine-engine/xine.c | 30 ++++--- src/xine-engine/xine_internal.h | 7 +- 11 files changed, 295 insertions(+), 132 deletions(-) diff --git a/src/xine-engine/audio_decoder.c b/src/xine-engine/audio_decoder.c index 32fb031e0..890298251 100644 --- a/src/xine-engine/audio_decoder.c +++ b/src/xine-engine/audio_decoder.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: audio_decoder.c,v 1.86 2002/10/18 04:04:10 miguelfreitas Exp $ + * $Id: audio_decoder.c,v 1.87 2002/10/29 16:02:43 mroi Exp $ * * * functions that implement audio decoding @@ -149,8 +149,6 @@ void *audio_decoder_loop (void *stream_gen) { case BUF_CONTROL_RESET_DECODER: if (stream->audio_decoder_plugin) stream->audio_decoder_plugin->reset (stream->audio_decoder_plugin); - if (stream->audio_out) - stream->audio_out->control(stream->audio_out, AO_CTRL_FLUSH_BUFFERS); break; case BUF_CONTROL_DISCONTINUITY: diff --git a/src/xine-engine/audio_out.c b/src/xine-engine/audio_out.c index 0c7310557..a17f438c8 100644 --- a/src/xine-engine/audio_out.c +++ b/src/xine-engine/audio_out.c @@ -17,7 +17,7 @@ * along with self program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_out.c,v 1.74 2002/10/24 17:51:30 guenter Exp $ + * $Id: audio_out.c,v 1.75 2002/10/29 16:02:45 mroi Exp $ * * 22-8-2001 James imported some useful AC3 sections from the previous alsa driver. * (c) 2001 Andy Lo A Foe @@ -136,11 +136,9 @@ static audio_fifo_t *fifo_new () { return fifo; } -static void fifo_append (audio_fifo_t *fifo, +static void fifo_append_int (audio_fifo_t *fifo, audio_buffer_t *buf) { - pthread_mutex_lock (&fifo->mutex); - buf->next = NULL; if (!fifo->first) { @@ -156,16 +154,19 @@ static void fifo_append (audio_fifo_t *fifo, fifo->num_buffers++; } - pthread_cond_signal (&fifo->not_empty); - pthread_mutex_unlock (&fifo->mutex); } -static audio_buffer_t *fifo_remove (audio_fifo_t *fifo) { - - audio_buffer_t *buf; +static void fifo_append (audio_fifo_t *fifo, + audio_buffer_t *buf) { pthread_mutex_lock (&fifo->mutex); + fifo_append_int (fifo, buf); + pthread_mutex_unlock (&fifo->mutex); +} + +static audio_buffer_t *fifo_remove_int (audio_fifo_t *fifo) { + audio_buffer_t *buf; while (!fifo->first) { pthread_cond_wait (&fifo->not_empty, &fifo->mutex); @@ -187,11 +188,21 @@ static audio_buffer_t *fifo_remove (audio_fifo_t *fifo) { } + return buf; +} + +static audio_buffer_t *fifo_remove (audio_fifo_t *fifo) { + + audio_buffer_t *buf; + + pthread_mutex_lock (&fifo->mutex); + buf = fifo_remove_int(fifo); pthread_mutex_unlock (&fifo->mutex); return buf; } + void write_pause_burst(ao_instance_t *this, uint32_t num_frames) { int error = 0; @@ -320,7 +331,7 @@ static void audio_filter_compress (ao_instance_t *this, int16_t *mem, int num_fr this->compression_factor = this->compression_factor_max; } -#if LOG +#ifdef LOG printf ("audio_out: max=%d f_max=%f compression_factor=%f\n", maxs, f_max, this->compression_factor); #endif @@ -471,11 +482,8 @@ static void *ao_loop (void *this_gen) { int64_t gap; int64_t delay; int64_t cur_time; - /* int num_output_frames ;*/ - /* int paused_wait; */ int64_t last_sync_time; int bufs_since_sync; - /* double acc_output_frames, output_frame_excess = 0; */ last_sync_time = bufs_since_sync = 0; #ifdef LOG @@ -490,12 +498,21 @@ static void *ao_loop (void *this_gen) { while ((this->audio_loop_running) || (!this->audio_loop_running && this->out_fifo->first)) { + + if (this->flush_audio_driver) { +#ifdef LOG + printf ("audio_out: flush audio driver\n"); +#endif + this->control(this, AO_CTRL_FLUSH_BUFFERS); + this->flush_audio_driver = 0; + } + /* wait until user unpauses stream audio_paused == 1 means we are playing at a different speed them we must process buffers otherwise the entire engine will stop. */ - while ( this->audio_paused ) { + while ( this->audio_paused && this->audio_loop_running ) { switch (this->audio_paused) { case 1: { @@ -512,7 +529,7 @@ static void *ao_loop (void *this_gen) { } case 2: { - this->metronom->allow_full_ao_fill_gap = 1; + this->allow_full_ao_fill_gap = 1; #ifdef LOG printf ("audio_out:loop:pause: I feel sleepy.\n"); #endif @@ -526,7 +543,7 @@ static void *ao_loop (void *this_gen) { } /* pthread_mutex_lock( &this->driver_lock ); What is this lock for ? */ delay = this->driver->delay(this->driver); - while (delay <=0) { + while (delay <=0 && this->audio_loop_running) { /* Get the audio card into RUNNING state. */ ao_fill_gap (this, 10000); /* FIXME, this PTS of 1000 should == period size */ delay = this->driver->delay(this->driver); @@ -586,8 +603,9 @@ static void *ao_loop (void *this_gen) { } else if ( abs(gap) < AO_MAX_GAP && abs(gap) > this->gap_tolerance && cur_time > (last_sync_time + SYNC_TIME_INVERVAL) && bufs_since_sync >= SYNC_BUF_INTERVAL ) { - +#ifdef LOG printf ("audio_out: audio_loop: ADJ_VPTS\n"); +#endif this->metronom->set_option(this->metronom, METRONOM_ADJ_VPTS_OFFSET, -gap/SYNC_GAP_RATE ); last_sync_time = cur_time; @@ -595,9 +613,9 @@ static void *ao_loop (void *this_gen) { } else if ( gap > AO_MAX_GAP ) { /* for big gaps output silence */ - if (this->metronom->allow_full_ao_fill_gap) { + if (this->allow_full_ao_fill_gap) { ao_fill_gap (this, gap); - this->metronom->allow_full_ao_fill_gap = 0; + this->allow_full_ao_fill_gap = 0; } else { ao_fill_gap (this, gap / 2); } @@ -955,6 +973,26 @@ static int ao_control (ao_instance_t *this, int cmd, ...) { return rval; } +static void ao_flush (ao_instance_t *this) { + audio_buffer_t *buf; + int i, num_buffers; + + pthread_mutex_lock (&this->out_fifo->mutex); + pthread_mutex_lock (&this->free_fifo->mutex); + num_buffers = this->out_fifo->num_buffers; + printf ("audio_out: flush fifo (%d buffers)\n", num_buffers); + + for (i = 0; i < this->out_fifo->num_buffers; i++) { + buf = fifo_remove_int (this->out_fifo); + fifo_append_int (this->free_fifo, buf); + } + + this->flush_audio_driver = 1; + this->allow_full_ao_fill_gap = 1; + pthread_mutex_unlock (&this->free_fifo->mutex); + pthread_mutex_unlock (&this->out_fifo->mutex); +} + ao_instance_t *ao_new_instance (xine_ao_driver_t *driver, xine_stream_t *stream) { @@ -971,19 +1009,22 @@ ao_instance_t *ao_new_instance (xine_ao_driver_t *driver, this->stream = stream; pthread_mutex_init( &this->driver_lock, NULL ); - this->open = ao_open; - this->get_buffer = ao_get_buffer; - this->put_buffer = ao_put_buffer; - this->close = ao_close; - this->exit = ao_exit; - this->get_capabilities = ao_get_capabilities; - this->get_property = ao_get_property; - this->set_property = ao_set_property; - this->control = ao_control; - this->audio_loop_running = 0; - this->audio_paused = 0; - this->zero_space = xine_xmalloc (ZERO_BUF_SIZE * 2 * 6); - this->gap_tolerance = driver->get_gap_tolerance (this->driver); + this->open = ao_open; + this->get_buffer = ao_get_buffer; + this->put_buffer = ao_put_buffer; + this->close = ao_close; + this->exit = ao_exit; + this->get_capabilities = ao_get_capabilities; + this->get_property = ao_get_property; + this->set_property = ao_set_property; + this->control = ao_control; + this->flush = ao_flush; + this->audio_loop_running = 0; + this->audio_paused = 0; + this->flush_audio_driver = 0; + this->allow_full_ao_fill_gap = 0; + this->zero_space = xine_xmalloc (ZERO_BUF_SIZE * 2 * 6); + this->gap_tolerance = driver->get_gap_tolerance (this->driver); this->resample_conf = config->register_enum (config, "audio.resample_mode", 0, resample_modes, diff --git a/src/xine-engine/audio_out.h b/src/xine-engine/audio_out.h index b22f1a7bc..5e1cedaa4 100644 --- a/src/xine-engine/audio_out.h +++ b/src/xine-engine/audio_out.h @@ -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: audio_out.h,v 1.39 2002/10/24 17:51:30 guenter Exp $ + * $Id: audio_out.h,v 1.40 2002/10/29 16:02:47 mroi Exp $ */ #ifndef HAVE_AUDIO_OUT_H #define HAVE_AUDIO_OUT_H @@ -201,7 +201,11 @@ struct ao_instance_s { */ int (*control) (ao_instance_t *this, int cmd, /* arg */ ...); - + /* + * Flush audio_out fifo. + */ + void (*flush) (ao_instance_t *this); + /* private stuff */ xine_ao_driver_t *driver; @@ -232,6 +236,8 @@ struct ao_instance_s { int16_t *zero_space; int64_t passthrough_offset; + int flush_audio_driver; + int allow_full_ao_fill_gap; int do_compress; double compression_factor; /* current compression */ diff --git a/src/xine-engine/demux.c b/src/xine-engine/demux.c index 7ccfaa8b4..ddbb9017f 100644 --- a/src/xine-engine/demux.c +++ b/src/xine-engine/demux.c @@ -56,6 +56,14 @@ void xine_demux_flush_engine (xine_stream_t *stream) { buf->type = BUF_CONTROL_RESET_DECODER; stream->audio_fifo->put (stream->audio_fifo, buf); } + + if (stream->video_out) { + stream->video_out->flush(stream->video_out); + } + + if (stream->audio_out) { + stream->audio_out->flush(stream->audio_out); + } stream->metronom->adjust_clock(stream->metronom, stream->metronom->get_current_time(stream->metronom) + 30 * 90000 ); diff --git a/src/xine-engine/metronom.c b/src/xine-engine/metronom.c index a779953f2..3635bdaa4 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.95 2002/10/28 07:53:52 tmattern Exp $ + * $Id: metronom.c,v 1.96 2002/10/29 16:02:48 mroi Exp $ */ #ifdef HAVE_CONFIG_H @@ -47,6 +47,7 @@ #define PREBUFFER_PTS_OFFSET 30000 #define VIDEO_DRIFT_TOLERANCE 45000 #define AUDIO_DRIFT_TOLERANCE 45000 +#define AV_DIFF_TOLERANCE 45000 /* redefine abs as macro to handle 64-bit diffs. i guess llabs may not be available everywhere */ @@ -262,17 +263,17 @@ static int64_t metronom_got_spu_packet (metronom_t *this, int64_t pts) { int64_t vpts, video_vpts, vpts_old, vpts_new; pthread_mutex_lock (&this->lock); - vpts_old = pts + this->vpts_offset; - vpts_new = pts + this->next_vpts_offset; + vpts_old = pts + this->old_vpts_offset; + vpts_new = pts + this->vpts_offset; video_vpts = this->video_vpts; if (pts >= 0 ) { - if ( abs(vpts_old - video_vpts) > abs(vpts_new - video_vpts) ) { - vpts = vpts_new; - } else { - vpts=vpts_old; - } - /* printf ("metronom: WARNING:got_spu_packet: vpts=%lld, old offset=%lld, new offset=%lld, video_vpts=%lld\n", vpts, vpts_old, vpts_new, video_vpts); */ + if ( abs(vpts_old - video_vpts) > abs(vpts_new - video_vpts) ) { + vpts = vpts_new; + } else { + vpts = vpts_old; + } + /* printf ("metronom: WARNING:got_spu_packet: vpts=%lld, old offset=%lld, new offset=%lld, video_vpts=%lld\n", vpts, vpts_old, vpts_new, video_vpts); */ } else { /* pts < 0 */ vpts = this->vpts_offset; @@ -285,11 +286,12 @@ static int64_t metronom_got_spu_packet (metronom_t *this, int64_t pts) { static void metronom_handle_video_discontinuity (metronom_t *this, int type, int64_t disc_off) { + int64_t diff; pthread_mutex_lock (&this->lock); #ifdef LOG - printf ("metronom: av_diff=%ld\n", this->video_vpts - this->audio_vpts); + printf ("metronom: av_diff=%lld\n", this->video_vpts - this->audio_vpts); #endif this->video_discontinuity_count++; @@ -307,55 +309,83 @@ static void metronom_handle_video_discontinuity (metronom_t *this, int type, pthread_cond_wait (&this->audio_discontinuity_reached, &this->lock); } - - 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->audio_vpts < metronom_get_current_time(this) ) { + this->audio_vpts = PREBUFFER_PTS_OFFSET + metronom_get_current_time(this); + printf ("metronom: audio vpts adjusted with prebuffer to %lld\n", this->audio_vpts); + } if ( this->video_vpts < metronom_get_current_time(this) ) { this->video_vpts = PREBUFFER_PTS_OFFSET + metronom_get_current_time(this); printf ("metronom: video vpts adjusted with prebuffer to %lld\n", this->video_vpts); } + + diff = this->video_vpts - this->audio_vpts; + if (abs(diff) > AV_DIFF_TOLERANCE) { + if (this->video_vpts > this->audio_vpts) + this->audio_vpts = this->video_vpts; + else + this->video_vpts = this->audio_vpts; + } else { + this->video_drift = diff; + this->video_drift_step = diff / 30; + } - if (this->in_discontinuity) - this->vpts_offset = this->next_vpts_offset; - + this->old_vpts_offset = this->vpts_offset; + switch (type) { case DISC_STREAMSTART: #ifdef LOG printf ("metronom: DISC_STREAMSTART\n"); #endif - this->vpts_offset = this->video_vpts; - this->in_discontinuity = 0; - this->force_audio_jump = 0; + if (this->video_vpts > this->audio_vpts) + this->vpts_offset = this->audio_vpts = this->video_vpts; + else + this->vpts_offset = this->video_vpts = this->audio_vpts; + this->video_discontinuity_pts = disc_off; + this->audio_discontinuity_pts = disc_off; + this->in_video_discontinuity = 0; + this->in_audio_discontinuity = 0; + this->force_audio_jump = 1; + this->force_video_jump = 1; + this->video_drift = 0; break; case DISC_ABSOLUTE: #ifdef LOG printf ("metronom: DISC_ABSOLUTE\n"); #endif - this->next_vpts_offset = this->video_vpts - disc_off; - this->in_discontinuity = 30; - this->force_audio_jump = 0; + this->vpts_offset = this->video_vpts - disc_off; + this->video_discontinuity_pts = disc_off; + this->audio_discontinuity_pts = disc_off; + this->in_video_discontinuity = 30; + this->in_audio_discontinuity = 30; + this->force_audio_jump = 0; + this->force_video_jump = 0; break; case DISC_RELATIVE: #ifdef LOG printf ("metronom: DISC_RELATIVE\n"); #endif - this->next_vpts_offset = this->vpts_offset - disc_off; - this->in_discontinuity = 30; - this->force_audio_jump = 0; + this->vpts_offset = this->vpts_offset - disc_off; + this->video_discontinuity_pts = this->video_vpts - this->vpts_offset; + this->audio_discontinuity_pts = this->audio_vpts - this->vpts_offset; + this->in_video_discontinuity = 30; + this->in_audio_discontinuity = 30; + this->force_audio_jump = 0; + this->force_video_jump = 0; break; case DISC_STREAMSEEK: #ifdef LOG printf ("metronom: DISC_STREAMSEEK\n"); #endif - this->vpts_offset = this->video_vpts - disc_off; - this->next_vpts_offset = this->video_vpts - disc_off; - this->in_discontinuity = 30; - this->force_audio_jump = 1; - this->allow_full_ao_fill_gap = 1; + this->vpts_offset = this->video_vpts - disc_off; + this->video_discontinuity_pts = disc_off; + this->audio_discontinuity_pts = disc_off; + this->in_video_discontinuity = 30; + this->in_audio_discontinuity = 30; + this->force_audio_jump = 1; + this->force_video_jump = 1; + this->video_drift = 0; break; } @@ -378,13 +408,17 @@ static void metronom_got_video_frame (metronom_t *this, vo_frame_t *img) { printf("metronom: got_video_frame pts = %lld\n", pts ); #endif - if (this->in_discontinuity) { - this->in_discontinuity--; + if (this->in_video_discontinuity) { + this->in_video_discontinuity--; - if (!this->in_discontinuity) - this->vpts_offset = this->next_vpts_offset; - else - pts = 0; /* ignore pts during discontinuities */ + if (pts) { + diff = pts - this->video_discontinuity_pts; + if (abs(diff) < VIDEO_DRIFT_TOLERANCE) { + this->in_video_discontinuity = 0; + } else { + pts = 0; /* ignore pts during discontinuities */ + } + } } this->img_cpt++; @@ -424,10 +458,10 @@ static void metronom_got_video_frame (metronom_t *this, vo_frame_t *img) { diff, this->video_vpts, vpts); #endif - if (abs (diff) > VIDEO_DRIFT_TOLERANCE) { - - this->video_vpts = vpts; - this->video_drift = 0; + if ((abs (diff) > VIDEO_DRIFT_TOLERANCE) || (this->force_video_jump)) { + this->force_video_jump = 0; + this->video_vpts = vpts; + this->video_drift = 0; printf ("metronom: video jump\n"); @@ -489,16 +523,6 @@ static void metronom_handle_audio_discontinuity (metronom_t *this, int type, pthread_cond_wait (&this->video_discontinuity_reached, &this->lock); } - if ( this->audio_vpts < metronom_get_current_time(this) ) { - this->audio_vpts = PREBUFFER_PTS_OFFSET + metronom_get_current_time(this); - printf ("metronom: audio vpts adjusted with prebuffer to %lld\n", this->audio_vpts); - } - - if ( this->audio_vpts < this->video_vpts ) { - this->audio_vpts = this->video_vpts; - printf ("metronom: audio vpts adjusted to %lld\n", this->audio_vpts); - } - /* next_vpts_offset, in_discontinuity is handled in expect_video_discontinuity */ while ( this->audio_discontinuity_count > this->discontinuity_handled_count ) { @@ -527,17 +551,28 @@ static int64_t metronom_got_audio_samples (metronom_t *this, int64_t pts, pthread_mutex_lock (&this->lock); - if (this->in_discontinuity && !this->force_audio_jump) - pts = 0; /* ignore pts during discontinuities */ + if (this->in_audio_discontinuity) { + this->in_audio_discontinuity--; + + if (pts) { + diff = pts - this->audio_discontinuity_pts; + if (abs(diff) < AUDIO_DRIFT_TOLERANCE) { + this->in_audio_discontinuity = 0; + } else { + pts = 0; /* ignore pts during discontinuities */ + } + } + } + if (pts) { vpts = pts + this->vpts_offset; diff = this->audio_vpts - vpts; /* compare predicted and given vpts */ - if( (abs(diff) > AUDIO_DRIFT_TOLERANCE) || this->force_audio_jump ) { - this->audio_vpts = vpts; - this->audio_drift_step = 0; + if((abs(diff) > AUDIO_DRIFT_TOLERANCE) || (this->force_audio_jump)) { this->force_audio_jump = 0; + this->audio_vpts = vpts; + this->audio_drift_step = 0; printf("metronom: audio jump\n"); } else { @@ -760,17 +795,17 @@ metronom_t * metronom_init (int have_audio, xine_stream_t *stream) { printf ("metronom: cannot create sync thread (%s)\n", strerror(err)); - this->av_offset = 0; - this->in_discontinuity = 0; - this->vpts_offset = 0; - this->next_vpts_offset = 0; + this->av_offset = 0; + this->vpts_offset = 0; + this->old_vpts_offset = 0; /* initialize video stuff */ - this->video_vpts = PREBUFFER_PTS_OFFSET; - this->video_drift = 0; - this->video_drift_step = 0; - this->video_discontinuity_count = 0; + this->video_vpts = PREBUFFER_PTS_OFFSET; + this->video_drift = 0; + this->video_drift_step = 0; + this->video_discontinuity_count = 0; + this->in_video_discontinuity = 0; this->discontinuity_handled_count = 0; pthread_cond_init (&this->video_discontinuity_reached, NULL); this->img_duration = 3000; @@ -780,10 +815,10 @@ metronom_t * metronom_init (int have_audio, xine_stream_t *stream) { /* initialize audio stuff */ - this->have_audio = have_audio; - this->audio_vpts = PREBUFFER_PTS_OFFSET; - this->audio_discontinuity_count = 0; - this->allow_full_ao_fill_gap = 0; + this->have_audio = have_audio; + this->audio_vpts = PREBUFFER_PTS_OFFSET; + this->in_audio_discontinuity = 0; + this->audio_discontinuity_count = 0; pthread_cond_init (&this->audio_discontinuity_reached, NULL); diff --git a/src/xine-engine/metronom.h b/src/xine-engine/metronom.h index 8baeece10..85d0c5eb6 100644 --- a/src/xine-engine/metronom.h +++ b/src/xine-engine/metronom.h @@ -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.h,v 1.38 2002/10/28 07:53:52 tmattern Exp $ + * $Id: metronom.h,v 1.39 2002/10/29 16:02:49 mroi Exp $ * * metronom: general pts => virtual calculation/assoc * @@ -217,9 +217,7 @@ struct metronom_s { int64_t audio_vpts; int64_t vpts_offset; - int64_t next_vpts_offset; - - int in_discontinuity; + int64_t old_vpts_offset; int64_t video_drift; int64_t video_drift_step; @@ -244,9 +242,15 @@ struct metronom_s { pthread_cond_t audio_discontinuity_reached; pthread_cond_t cancel; - int allow_full_ao_fill_gap; + int force_video_jump; int force_audio_jump; + int64_t video_discontinuity_pts; + int64_t audio_discontinuity_pts; + + int in_video_discontinuity; + int in_audio_discontinuity; + int64_t img_duration; int img_cpt; int64_t last_video_pts; diff --git a/src/xine-engine/video_decoder.c b/src/xine-engine/video_decoder.c index 90915ef3d..9b3eff3ba 100644 --- a/src/xine-engine/video_decoder.c +++ b/src/xine-engine/video_decoder.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_decoder.c,v 1.105 2002/10/27 01:52:15 guenter Exp $ + * $Id: video_decoder.c,v 1.106 2002/10/29 16:02:49 mroi Exp $ * */ @@ -206,6 +206,14 @@ void *video_decoder_loop (void *stream_gen) { buf->decoder_flags & BUF_FLAG_END_STREAM); } + /* Wake up xine_play if it's waiting for a frame */ + pthread_mutex_lock (&stream->first_frame_lock); + if (stream->first_frame_flag) { + stream->first_frame_flag = 0; + pthread_cond_signal(&stream->first_frame_reached); + } + pthread_mutex_unlock (&stream->first_frame_lock); + break; case BUF_CONTROL_QUIT: diff --git a/src/xine-engine/video_out.c b/src/xine-engine/video_out.c index 8c10a1b1f..f89daa873 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.106 2002/10/16 22:54:48 guenter Exp $ + * $Id: video_out.c,v 1.107 2002/10/29 16:02:50 mroi Exp $ * * frame allocation / queuing / scheduling / output functions */ @@ -109,11 +109,9 @@ static img_buf_fifo_t *vo_new_img_buf_queue () { return queue; } -static void vo_append_to_img_buf_queue (img_buf_fifo_t *queue, +static void vo_append_to_img_buf_queue_int (img_buf_fifo_t *queue, vo_frame_t *img) { - pthread_mutex_lock (&queue->mutex); - /* img already enqueue? (serious leak) */ assert (img->next==NULL); @@ -132,14 +130,18 @@ static void vo_append_to_img_buf_queue (img_buf_fifo_t *queue, queue->num_buffers++; pthread_cond_signal (&queue->not_empty); +} + +static void vo_append_to_img_buf_queue (img_buf_fifo_t *queue, + vo_frame_t *img) { + pthread_mutex_lock (&queue->mutex); + vo_append_to_img_buf_queue_int (queue, img); pthread_mutex_unlock (&queue->mutex); } -static vo_frame_t *vo_remove_from_img_buf_queue (img_buf_fifo_t *queue) { +static vo_frame_t *vo_remove_from_img_buf_queue_int (img_buf_fifo_t *queue) { vo_frame_t *img; - pthread_mutex_lock (&queue->mutex); - while (!queue->first || queue->locked_for_read) { pthread_cond_wait (&queue->not_empty, &queue->mutex); } @@ -158,6 +160,14 @@ static vo_frame_t *vo_remove_from_img_buf_queue (img_buf_fifo_t *queue) { } } + return img; +} + +static vo_frame_t *vo_remove_from_img_buf_queue (img_buf_fifo_t *queue) { + vo_frame_t *img; + + pthread_mutex_lock (&queue->mutex); + img = vo_remove_from_img_buf_queue_int(queue); pthread_mutex_unlock (&queue->mutex); return img; @@ -279,6 +289,17 @@ static int vo_frame_draw (vo_frame_t *img) { } if (!img->bad_frame) { + + /* + * Wake up xine_play if it's waiting for a frame + */ + pthread_mutex_lock (&this->stream->first_frame_lock); + if (this->stream->first_frame_flag) { + this->stream->first_frame_flag = 0; + pthread_cond_signal(&this->stream->first_frame_reached); + } + pthread_mutex_unlock (&this->stream->first_frame_lock); + /* * put frame into FIFO-Buffer */ @@ -703,7 +724,7 @@ static void *video_out_loop (void *this_gen) { printf ("video_out: displaying frame (id=%d)\n", img->id); #endif overlay_and_display_frame (this, img, vpts); - } + } else { check_redraw_needed( this, vpts ); @@ -886,6 +907,29 @@ static void vo_enable_overlay (vo_instance_t *this_gen, int overlay_enabled) { this->overlay_enabled = overlay_enabled; } +/* + * Flush video_out fifo + */ +static void vo_flush (vo_instance_t *this_gen) { + vos_t *this = (vos_t *) this_gen; + vo_frame_t *img; + int i, num_buffers; + + pthread_mutex_lock (&this->display_img_buf_queue->mutex); + pthread_mutex_lock (&this->free_img_buf_queue->mutex); + num_buffers = this->display_img_buf_queue->num_buffers; + + /* don't flush the last img, it improves seeking */ + printf ("video_out: flush fifo (%d buffers)\n", num_buffers); + for (i = 1; i < num_buffers; i++) { + img = vo_remove_from_img_buf_queue_int (this->display_img_buf_queue); + vo_append_to_img_buf_queue_int (this->free_img_buf_queue, img); + } + + pthread_mutex_unlock (&this->free_img_buf_queue->mutex); + pthread_mutex_unlock (&this->display_img_buf_queue->mutex); +} + vo_instance_t *vo_new_instance (xine_vo_driver_t *driver, xine_stream_t *stream) { @@ -912,6 +956,7 @@ vo_instance_t *vo_new_instance (xine_vo_driver_t *driver, this->vo.get_capabilities = vo_get_capabilities; this->vo.enable_ovl = vo_enable_overlay; this->vo.get_overlay_instance = vo_get_overlay_instance; + this->vo.flush = vo_flush; this->num_frames_delivered = 0; this->num_frames_skipped = 0; diff --git a/src/xine-engine/video_out.h b/src/xine-engine/video_out.h index 17d956868..275fcd0d0 100644 --- a/src/xine-engine/video_out.h +++ b/src/xine-engine/video_out.h @@ -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.h,v 1.68 2002/10/26 14:45:28 mroi Exp $ + * $Id: video_out.h,v 1.69 2002/10/29 16:02:50 mroi Exp $ * * * xine version of video_out.h @@ -150,6 +150,9 @@ struct vo_instance_s { /* get overlay instance (overlay source) */ video_overlay_instance_t* (*get_overlay_instance) (vo_instance_t *this); + /* flush video_out fifo */ + void (*flush) (vo_instance_t *this); + /* private stuff can be added here */ }; diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c index 43ee01788..edda8b025 100644 --- a/src/xine-engine/xine.c +++ b/src/xine-engine/xine.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: xine.c,v 1.182 2002/10/29 03:31:38 guenter Exp $ + * $Id: xine.c,v 1.183 2002/10/29 16:02:51 mroi Exp $ * * top-level xine functions * @@ -113,7 +113,7 @@ static void xine_set_speed_internal (xine_stream_t *stream, int speed) { * samples from the sound driver */ if (speed != XINE_SPEED_NORMAL && speed != XINE_SPEED_PAUSE) - stream->audio_out->control(stream->audio_out, AO_CTRL_FLUSH_BUFFERS); + stream->audio_out->flush(stream->audio_out); stream->audio_out->control(stream->audio_out, speed == XINE_SPEED_PAUSE ? AO_CTRL_PLAY_PAUSE : AO_CTRL_PLAY_RESUME); @@ -187,10 +187,6 @@ static void xine_stop_internal (xine_stream_t *stream) { printf ("xine_stop: demux stopped\n"); #endif - /* remove buffered samples from the sound device driver */ - if (stream->audio_out) - stream->audio_out->control (stream->audio_out, AO_CTRL_FLUSH_BUFFERS); - #ifdef LOG printf ("xine_stop: done\n"); #endif @@ -318,6 +314,9 @@ xine_stream_t *xine_stream_new (xine_t *this, pthread_mutex_init (&stream->osd_lock, NULL); pthread_mutex_init (&stream->counter_lock, NULL); pthread_cond_init (&stream->counter_changed, NULL); + pthread_mutex_init (&stream->first_frame_lock, NULL); + pthread_cond_init (&stream->first_frame_reached, NULL); + /* * event queues @@ -412,10 +411,6 @@ static int xine_open_internal (xine_stream_t *stream, const char *mrl) { _("xine: couldn't find demux for >%s<\n"), mrl); stream->err = XINE_ERROR_NO_DEMUX_PLUGIN; - /* remove buffered samples from the sound device driver */ - if (stream->audio_out) - stream->audio_out->control (stream->audio_out, AO_CTRL_FLUSH_BUFFERS); - stream->status = XINE_STATUS_STOP; return 0; } @@ -509,6 +504,17 @@ static int xine_play_internal (xine_stream_t *stream, int start_pos, int start_t if (stream->speed != XINE_SPEED_NORMAL) xine_set_speed_internal (stream, XINE_SPEED_NORMAL); + /* Wait until the first frame produced by the previous + * xine_play call is pushed into the video_out fifo + * see video_out.c + */ + pthread_mutex_lock (&stream->first_frame_lock); + /* FIXME: howto detect if video frames will be produced */ + if (stream->first_frame_flag && stream->video_decoder_plugin) { + pthread_cond_wait(&stream->first_frame_reached, &stream->first_frame_lock); + } + pthread_mutex_unlock (&stream->first_frame_lock); + /* * start/seek demux */ @@ -544,6 +550,10 @@ static int xine_play_internal (xine_stream_t *stream, int start_pos, int start_t stream->status = XINE_STATUS_PLAY; } + pthread_mutex_lock (&stream->first_frame_lock); + stream->first_frame_flag = 1; + pthread_mutex_unlock (&stream->first_frame_lock); + printf ("xine: xine_play_internal ...done\n"); return 1; diff --git a/src/xine-engine/xine_internal.h b/src/xine-engine/xine_internal.h index 0f7e8baec..1eb4b5fae 100644 --- a/src/xine-engine/xine_internal.h +++ b/src/xine-engine/xine_internal.h @@ -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: xine_internal.h,v 1.108 2002/10/28 03:24:44 miguelfreitas Exp $ + * $Id: xine_internal.h,v 1.109 2002/10/29 16:02:54 mroi Exp $ * */ @@ -190,6 +190,11 @@ struct xine_stream_s { int stream_info[XINE_STREAM_INFO_MAX]; char *meta_info [XINE_STREAM_INFO_MAX]; + /* seeking slowdown */ + int first_frame_flag; + pthread_mutex_t first_frame_lock; + pthread_cond_t first_frame_reached; + /* wait for headers sent / stream decoding finished */ pthread_mutex_t counter_lock; pthread_cond_t counter_changed; -- cgit v1.2.3