summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiguel Freitas <miguelfreitas@users.sourceforge.net>2002-12-22 23:30:29 +0000
committerMiguel Freitas <miguelfreitas@users.sourceforge.net>2002-12-22 23:30:29 +0000
commitf9ec6c1ef7bc1b6aa7cd086408c14115502053aa (patch)
treed1b183136525edbf9ebd1716d39890a77cce247a
parent2719c56c147846b7730cc94b44220009ba1ddd8c (diff)
downloadxine-lib-f9ec6c1ef7bc1b6aa7cd086408c14115502053aa.tar.gz
xine-lib-f9ec6c1ef7bc1b6aa7cd086408c14115502053aa.tar.bz2
flush/seeking overhauled
- move frame discarding to inside the output loopss. it is much safer to manipulate fifos from there avoiding any races. - do not reject audio frames because vpts is smaller than previous. it might happen on seeking but it's ok, because the sound driver may have being flushed too. - fix xine_demux_flush_engine so it doesn't call output flush too early - remove scr adjusting please report any problems... CVS patchset: 3639 CVS date: 2002/12/22 23:30:29
-rw-r--r--src/xine-engine/audio_out.c72
-rw-r--r--src/xine-engine/demux.c38
-rw-r--r--src/xine-engine/video_out.c101
-rw-r--r--src/xine-engine/xine.c28
4 files changed, 123 insertions, 116 deletions
diff --git a/src/xine-engine/audio_out.c b/src/xine-engine/audio_out.c
index 7aa771866..6a786f2fc 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.91 2002/12/21 16:12:25 miguelfreitas Exp $
+ * $Id: audio_out.c,v 1.92 2002/12/22 23:30:29 miguelfreitas Exp $
*
* 22-8-2001 James imported some useful AC3 sections from the previous alsa driver.
* (c) 2001 Andy Lo A Foe <andy@alsaplayer.org>
@@ -524,11 +524,32 @@ static void *ao_loop (void *this_gen) {
}
if (this->flush_audio_driver) {
+ audio_buffer_t *buf;
+ int num_buffers;
#ifdef LOG
printf ("audio_out: flush audio driver\n");
#endif
+ pthread_mutex_lock (&this->out_fifo->mutex);
+
+ num_buffers = this->out_fifo->num_buffers;
+
+ printf ("audio_out: flush fifo (%d buffers)\n", num_buffers);
+
+ while ( num_buffers-- ) {
+ buf = fifo_remove_int (this->out_fifo);
+ fifo_append (this->free_fifo, buf);
+ }
+
+ pthread_mutex_unlock (&this->out_fifo->mutex);
+
+ if (in_buf) {
+ fifo_append (this->free_fifo, in_buf);
+ in_buf = NULL;
+ }
+
this->control(this, AO_CTRL_FLUSH_BUFFERS);
this->flush_audio_driver = 0;
+ continue;
}
/*
@@ -862,20 +883,8 @@ static void ao_put_buffer (xine_audio_port_t *this, audio_buffer_t *buf, xine_st
pts, buf->vpts);
#endif
- if ( buf->vpts + AO_MAX_GAP < this->last_audio_vpts) {
-
- /* reject buffer */
- printf ("audio_out: rejected buffer vpts=%lld, last_audio_vpts=%lld\n",
- buf->vpts, this->last_audio_vpts);
-
- fifo_append (this->free_fifo, buf);
-
- } else {
-
- fifo_append (this->out_fifo, buf);
- this->last_audio_vpts = buf->vpts;
-
- }
+ fifo_append (this->out_fifo, buf);
+ this->last_audio_vpts = buf->vpts;
#ifdef LOG
printf ("audio_out: ao_put_buffer done\n");
@@ -1042,31 +1051,18 @@ static int ao_control (xine_audio_port_t *this, int cmd, ...) {
static void ao_flush (xine_audio_port_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 < num_buffers; i++) {
- buf = fifo_remove_int (this->out_fifo);
- fifo_append_int (this->free_fifo, buf);
+ if( this->audio_loop_running ) {
+ this->flush_audio_driver = 1;
+
+ buf = fifo_remove (this->free_fifo);
+ buf->num_frames = 0;
+ fifo_append (this->out_fifo, buf);
+
+ /* do not try this in paused mode */
+ while( this->flush_audio_driver )
+ xine_usec_sleep (20000); /* pthread_cond_t could be used here */
}
-
- /*
- * make sure ao_loop can savely quit
- */
-
- buf = fifo_remove_int (this->free_fifo);
- buf->num_frames = 0;
- fifo_append_int (this->out_fifo, buf);
-
- this->flush_audio_driver = 1;
- pthread_mutex_unlock (&this->free_fifo->mutex);
- pthread_mutex_unlock (&this->out_fifo->mutex);
}
xine_audio_port_t *ao_new_port (xine_t *xine, ao_driver_t *driver) {
diff --git a/src/xine-engine/demux.c b/src/xine-engine/demux.c
index 5f4ce9d70..20474d71f 100644
--- a/src/xine-engine/demux.c
+++ b/src/xine-engine/demux.c
@@ -31,8 +31,9 @@
#include "demuxers/demux.h"
#include "buffer.h"
+/*
#define LOG
-
+*/
/* internal use only - called from demuxers on seek/stop
* warning: after clearing decoders fifos an absolute discontinuity
@@ -57,6 +58,11 @@ void xine_demux_flush_engine (xine_stream_t *stream) {
buf->type = BUF_CONTROL_RESET_DECODER;
stream->audio_fifo->put (stream->audio_fifo, buf);
}
+
+ /* on seeking we must wait decoder fifos to process before doing flush.
+ * otherwise we flush too early (before the old data has left decoders)
+ */
+ xine_demux_control_headers_done (stream);
if (stream->video_out) {
stream->video_out->flush(stream->video_out);
@@ -65,11 +71,6 @@ void xine_demux_flush_engine (xine_stream_t *stream) {
if (stream->audio_out) {
stream->audio_out->flush(stream->audio_out);
}
-
- /* FIXME: Messing with the clock is bad as long as the clock is global to all streams.
- * But it is currently the best solution to have good seeking performance. */
- stream->xine->clock->adjust_clock(stream->xine->clock,
- stream->xine->clock->get_current_time(stream->xine->clock) + 30 * 90000 );
}
@@ -92,10 +93,21 @@ void xine_demux_control_newpts( xine_stream_t *stream, int64_t pts, uint32_t fla
}
}
+/* sync with decoder fifos, making sure everything gets processed */
void xine_demux_control_headers_done (xine_stream_t *stream) {
+ int header_count_audio;
+ int header_count_video;
buf_element_t *buf;
-
+
+ pthread_mutex_lock (&stream->counter_lock);
+ if (stream->audio_fifo)
+ header_count_audio = stream->header_count_audio + 1;
+ else
+ header_count_audio = 0;
+
+ header_count_video = stream->header_count_video + 1;
+
buf = stream->video_fifo->buffer_pool_alloc (stream->video_fifo);
buf->type = BUF_CONTROL_HEADERS_DONE;
stream->video_fifo->put (stream->video_fifo, buf);
@@ -105,6 +117,18 @@ void xine_demux_control_headers_done (xine_stream_t *stream) {
buf->type = BUF_CONTROL_HEADERS_DONE;
stream->audio_fifo->put (stream->audio_fifo, buf);
}
+
+ while ((stream->header_count_audio<header_count_audio) ||
+ (stream->header_count_video<header_count_video)) {
+#ifdef LOG
+ printf ("xine: waiting for headers.\n");
+#endif
+ pthread_cond_wait (&stream->counter_changed, &stream->counter_lock);
+ }
+#ifdef LOG
+ printf ("xine: headers processed.\n");
+#endif
+ pthread_mutex_unlock (&stream->counter_lock);
}
void xine_demux_control_start( xine_stream_t *stream ) {
diff --git a/src/xine-engine/video_out.c b/src/xine-engine/video_out.c
index 16611629e..356a261bf 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.123 2002/12/22 15:02:07 miguelfreitas Exp $
+ * $Id: video_out.c,v 1.124 2002/12/22 23:30:29 miguelfreitas Exp $
*
* frame allocation / queuing / scheduling / output functions
*/
@@ -63,6 +63,7 @@ typedef struct {
vo_frame_t *last_frame;
vo_frame_t *img_backup;
int redraw_needed;
+ int flush_frames;
int video_loop_running;
int video_opened;
@@ -477,56 +478,67 @@ static void expire_frames (vos_t *this, int64_t cur_vpts) {
diff = 1000000; /* always enter the while-loop */
- while (img && (diff > img->duration)) {
+ while (img && (diff > img->duration || this->flush_frames)) {
pts = img->vpts;
diff = cur_vpts - pts;
- if (diff > img->duration) {
+ if (diff > img->duration || this->flush_frames) {
- /* do not print this message in stop/exit (scr is adjusted to force
- * discarding audio and video frames)
- */
- if( diff < 20 * 90000 )
+ if( !this->flush_frames ) {
xine_log(this->xine, XINE_LOG_MSG,
_("video_out: throwing away image with pts %lld because "
"it's too old (diff : %lld).\n"), pts, diff);
- this->num_frames_discarded++;
-
+ this->num_frames_discarded++;
+ }
+
img = vo_remove_from_img_buf_queue_int (this->display_img_buf_queue);
extra_info_merge( img->stream->current_extra_info, img->extra_info );
- /*
- * last frame? back it up for
- * still frame creation
- */
-
- if (!this->display_img_buf_queue->first) {
+ /* when flushing frames, keep the first one as backup */
+ if( this->flush_frames ) {
+
+ if (!this->img_backup) {
+ this->img_backup = img;
+
+ this->redraw_needed = 1;
+ } else {
+ vo_frame_dec_lock( img );
+ }
+
+ } else {
+ /*
+ * last frame? back it up for
+ * still frame creation
+ */
+
+ if (!this->display_img_buf_queue->first) {
- if (this->img_backup) {
+ if (this->img_backup) {
#ifdef LOG
- printf("video_out: overwriting frame backup\n");
+ printf("video_out: overwriting frame backup\n");
#endif
- vo_frame_dec_lock( this->img_backup );
- }
+ vo_frame_dec_lock( this->img_backup );
+ }
#ifdef LOG
- printf("video_out: possible still frame (old)\n");
+ printf("video_out: possible still frame (old)\n");
#endif
- this->img_backup = img;
+ this->img_backup = img;
- /* wait 4 frames before drawing this one.
- this allow slower systems to recover. */
- this->redraw_needed = 4;
- } else {
- vo_frame_dec_lock( img );
+ /* wait 4 frames before drawing this one.
+ this allow slower systems to recover. */
+ this->redraw_needed = 4;
+ } else {
+ vo_frame_dec_lock( img );
+ }
}
-
img = this->display_img_buf_queue->first;
}
}
-
+ this->flush_frames = 0;
+
pthread_mutex_unlock(&this->display_img_buf_queue->mutex);
}
@@ -737,6 +749,8 @@ static void *video_out_loop (void *this_gen) {
vos_t *this = (vos_t *) this_gen;
int64_t frame_duration, next_frame_vpts;
int64_t usec_to_sleep;
+
+ /* nice(-2); */
/*
* here it is - the heart of xine (or rather: one of the hearts
@@ -886,6 +900,7 @@ static void vo_open (xine_video_port_t *this_gen, xine_stream_t *stream) {
vos_t *this = (vos_t *) this_gen;
this->video_opened = 1;
+ this->flush_frames = 0;
this->last_delivery_pts = 0;
if (!this->overlay_enabled && stream->spu_channel_user > -2)
/* enable overlays if our new stream might want to show some */
@@ -1012,28 +1027,16 @@ static void vo_enable_overlay (xine_video_port_t *this_gen, int overlay_enabled)
*/
static void vo_flush (xine_video_port_t *this_gen) {
vos_t *this = (vos_t *) this_gen;
- vo_frame_t *img, *first;
- int i, num_buffers;
-
- pthread_mutex_lock (&this->display_img_buf_queue->mutex);
- num_buffers = this->display_img_buf_queue->num_buffers;
- /* we keep the first frame so that we have something to display when
- * seeking wildly around, but we schedule it in the past, so that it
- * will expire immediately and does not block anything */
- first = this->display_img_buf_queue->first;
- if (first) {
- vo_frame_inc_lock(first);
- first->vpts -= 30 * 90000;
- }
- printf ("video_out: flush fifo (%d buffers)\n", num_buffers);
- for (i = 0; i < num_buffers; i++) {
- img = vo_remove_from_img_buf_queue_int (this->display_img_buf_queue);
- vo_frame_dec_lock( img );
+
+ if( this->video_loop_running ) {
+ pthread_mutex_lock(&this->display_img_buf_queue->mutex);
+ this->flush_frames = 1;
+ pthread_mutex_unlock(&this->display_img_buf_queue->mutex);
+
+ /* do not try this in paused mode */
+ while(this->flush_frames)
+ xine_usec_sleep (20000); /* pthread_cond_t could be used here */
}
- if (first)
- vo_append_to_img_buf_queue_int(this->display_img_buf_queue, first);
- this->redraw_needed = 1;
- pthread_mutex_unlock (&this->display_img_buf_queue->mutex);
}
diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c
index 31d13ca11..94c1e81cd 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.201 2002/12/21 16:13:43 miguelfreitas Exp $
+ * $Id: xine.c,v 1.202 2002/12/22 23:30:29 miguelfreitas Exp $
*
* top-level xine functions
*
@@ -134,7 +134,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->flush(stream->audio_out);
+ stream->audio_out->control (stream->audio_out, AO_CTRL_FLUSH_BUFFERS);
stream->audio_out->control(stream->audio_out,
speed == XINE_SPEED_PAUSE ? AO_CTRL_PLAY_PAUSE : AO_CTRL_PLAY_RESUME);
@@ -380,8 +380,6 @@ xine_stream_t *xine_stream_new (xine_t *this,
static int xine_open_internal (xine_stream_t *stream, const char *mrl) {
- int header_count_audio;
- int header_count_video;
char *stream_setup;
#ifdef LOG
@@ -644,9 +642,11 @@ static int xine_open_internal (xine_stream_t *stream, const char *mrl) {
stream->err = XINE_ERROR_NO_DEMUX_PLUGIN;
/* remove buffered samples from the sound device driver */
- if (stream->audio_out)
+ /* why? */
+ /*if (stream->audio_out)
stream->audio_out->control (stream->audio_out, AO_CTRL_FLUSH_BUFFERS);
-
+ */
+
stream->status = XINE_STATUS_STOP;
printf ("xine: return from xine_open_internal\n");
@@ -654,24 +654,8 @@ static int xine_open_internal (xine_stream_t *stream, const char *mrl) {
return 0;
}
- pthread_mutex_lock (&stream->counter_lock);
- if (stream->audio_fifo)
- header_count_audio = stream->header_count_audio + 1;
- else
- header_count_audio = 0;
-
- header_count_video = stream->header_count_video + 1;
-
xine_demux_control_headers_done (stream);
- while ((stream->header_count_audio<header_count_audio) ||
- (stream->header_count_video<header_count_video)) {
- printf ("xine: waiting for headers.\n");
- pthread_cond_wait (&stream->counter_changed, &stream->counter_lock);
- }
- printf ("xine: headers processed.\n");
- pthread_mutex_unlock (&stream->counter_lock);
-
#ifdef LOG
printf ("xine: xine_open_internal done\n");
#endif