From f3265672dc2071d68740903a6b562e9d988f6343 Mon Sep 17 00:00:00 2001 From: Guenter Bartsch Date: Sat, 25 Aug 2001 07:12:16 +0000 Subject: fixed seeking (back to the old method), implementing true pause function, introducing trick playback (slow motion and fast forward) CVS patchset: 482 CVS date: 2001/08/25 07:12:16 --- src/xine-engine/audio_decoder.c | 10 ++- src/xine-engine/metronom.c | 133 ++++++++++++++-------------- src/xine-engine/metronom.h | 28 ++++-- src/xine-engine/xine.c | 189 +++++++++++++++++++--------------------- src/xine-engine/xine_internal.h | 31 ++++++- 5 files changed, 217 insertions(+), 174 deletions(-) (limited to 'src') diff --git a/src/xine-engine/audio_decoder.c b/src/xine-engine/audio_decoder.c index 07d64114b..ca701d0ad 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.28 2001/08/15 11:35:47 f1rmb Exp $ + * $Id: audio_decoder.c,v 1.29 2001/08/25 07:12:16 guenter Exp $ * * * functions that implement audio decoding @@ -116,6 +116,14 @@ void *audio_decoder_loop (void *this_gen) { break; default: + + while (this->audio_mute==2) { + usleep (50000); + } + + if (this->audio_mute) + break; + if ( (buf->type & 0xFF000000) == BUF_AUDIO_BASE ) { /* printf ("audio_decoder: got an audio buffer, type %08x\n", buf->type); */ diff --git a/src/xine-engine/metronom.c b/src/xine-engine/metronom.c index 40e1c59aa..694646bf3 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.18 2001/08/14 08:21:41 ehasenle Exp $ + * $Id: metronom.c,v 1.19 2001/08/25 07:12:16 guenter Exp $ */ #ifdef HAVE_CONFIG_H @@ -56,101 +56,93 @@ */ typedef struct unixscr_s { - scr_plugin_t scr; - struct timeval start_time; - uint32_t start_pts; - uint32_t last_pts; - pthread_mutex_t lock; - float speed; + scr_plugin_t scr; + + struct timeval cur_time; + uint32_t cur_pts; + double speed_factor; + + pthread_mutex_t lock; + } unixscr_t; static int unixscr_get_priority (scr_plugin_t *scr) { return 5; /* low priority */ } -static void unixscr_set_speed (scr_plugin_t *scr, float ticks_ps) { - unixscr_t *self = (unixscr_t*) scr; - uint32_t now = scr->get_current(scr); +static int unixscr_set_speed (scr_plugin_t *scr, int speed) { + unixscr_t *this = (unixscr_t*) scr; - pthread_mutex_lock (&self->lock); - - gettimeofday(&self->start_time, NULL); - self->last_pts = self->start_pts = now; - self->speed = ticks_ps; /* ticks per second */ + pthread_mutex_lock (&this->lock); + + this->speed_factor = (double) speed * 90000.0 / 4.0; + + pthread_mutex_unlock (&this->lock); - pthread_mutex_unlock (&self->lock); + return speed; } static void unixscr_adjust (scr_plugin_t *scr, uint32_t vpts) { - unixscr_t *self = (unixscr_t*) scr; + unixscr_t *this = (unixscr_t*) scr; - int delta; - int32_t current_time = self->scr.get_current(&self->scr); - - pthread_mutex_lock (&self->lock); + pthread_mutex_lock (&this->lock); - /* FIXME: this should be softer than a brute force warp... */ - delta = vpts; - delta -= current_time; - self->start_pts += delta; - /* TODO: remove */ - printf("adjusting start_pts to %d\n", self->start_pts); + this->cur_pts = vpts; + gettimeofday(&this->cur_time, NULL); - pthread_mutex_unlock (&self->lock); + pthread_mutex_unlock (&this->lock); } static void unixscr_start (scr_plugin_t *scr, uint32_t start_vpts) { - unixscr_t *self = (unixscr_t*) scr; - - pthread_mutex_lock (&self->lock); + unixscr_t *this = (unixscr_t*) scr; - gettimeofday(&self->start_time, NULL); - self->last_pts = self->start_pts = start_vpts; - self->speed = REALTIME_PTS; + pthread_mutex_lock (&this->lock); - pthread_mutex_unlock (&self->lock); + gettimeofday(&this->cur_time, NULL); + this->cur_pts = start_vpts; + pthread_mutex_unlock (&this->lock); } static uint32_t unixscr_get_current (scr_plugin_t *scr) { - unixscr_t *self = (unixscr_t*) scr; + unixscr_t *this = (unixscr_t*) scr; + struct timeval tv; uint32_t pts; - struct timeval tv; - - pthread_mutex_lock (&self->lock); + + pthread_mutex_lock (&this->lock); gettimeofday(&tv, NULL); - pts = (tv.tv_sec - self->start_time.tv_sec) * self->speed; - pts += (tv.tv_usec - self->start_time.tv_usec) * self->speed / 1e6; - pts += self->start_pts; - - if (self->last_pts > pts) { - /* printf("metronom: get_current_time(): timer STOPPED!\n"); */ - pts = self->last_pts; - } - pthread_mutex_unlock (&self->lock); + this->cur_pts += (tv.tv_sec - this->cur_time.tv_sec) * this->speed_factor; + this->cur_pts += (tv.tv_usec - this->cur_time.tv_usec) * this->speed_factor / 1e6; + + pts = this->cur_pts; + memcpy (&this->cur_time, &tv, sizeof (tv)); + + pthread_mutex_unlock (&this->lock); return pts; } static scr_plugin_t* unixscr_init () { - unixscr_t *self; + unixscr_t *this; - self = malloc(sizeof(*self)); - memset(self, 0, sizeof(*self)); + this = malloc(sizeof(*this)); + memset(this, 0, sizeof(*this)); - self->scr.interface_version = 1; - self->scr.get_priority = unixscr_get_priority; - self->scr.set_speed = unixscr_set_speed; - self->scr.adjust = unixscr_adjust; - self->scr.start = unixscr_start; - self->scr.get_current = unixscr_get_current; + this->scr.interface_version = 2; + this->scr.get_priority = unixscr_get_priority; + this->scr.set_speed = unixscr_set_speed; + this->scr.adjust = unixscr_adjust; + this->scr.start = unixscr_start; + this->scr.get_current = unixscr_get_current; - pthread_mutex_init (&self->lock, NULL); + unixscr_set_speed (&this->scr, SPEED_NORMAL); + + pthread_mutex_init (&this->lock, NULL); - return &self->scr; + return &this->scr; } @@ -176,22 +168,34 @@ static uint32_t metronom_get_current_time (metronom_t *this) { static void metronom_stop_clock(metronom_t *this) { scr_plugin_t** scr; for (scr = this->scr_list; scr < this->scr_list+MAX_SCR_PROVIDERS; scr++) - if (*scr) (*scr)->set_speed(*scr, 0.0); + if (*scr) (*scr)->set_speed(*scr, SPEED_PAUSE); } static void metronom_resume_clock(metronom_t *this) { scr_plugin_t** scr; for (scr = this->scr_list; scr < this->scr_list+MAX_SCR_PROVIDERS; scr++) - if (*scr) (*scr)->set_speed(*scr, REALTIME_PTS); + if (*scr) (*scr)->set_speed(*scr, SPEED_NORMAL); } -static void metronom_adjust_clock(metronom_t *this, uint32_t desired_pts) -{ +static void metronom_adjust_clock(metronom_t *this, uint32_t desired_pts) { this->scr_master->adjust(this->scr_master, desired_pts); } +static int metronom_set_speed (metronom_t *this, int speed) { + + scr_plugin_t **scr; + int true_speed; + + true_speed = this->scr_master->set_speed (this->scr_master, speed); + + for (scr = this->scr_list; scr < this->scr_list+MAX_SCR_PROVIDERS; scr++) + if (*scr) (*scr)->set_speed(*scr, true_speed); + + return true_speed; +} + /* * virtual pts calculation */ @@ -603,7 +607,7 @@ static scr_plugin_t* get_master_scr(metronom_t *this) { static int metronom_register_scr (metronom_t *this, scr_plugin_t *scr) { int i; - if (scr->interface_version != 1) return -1; + if (scr->interface_version != 2) return -1; for (i=0; iscr_list[i] == NULL) break; @@ -668,6 +672,7 @@ metronom_t * metronom_init (int have_audio) { this->adjust_clock = metronom_adjust_clock; this->register_scr = metronom_register_scr; this->unregister_scr = metronom_unregister_scr; + this->set_speed = metronom_set_speed; this->scr_list = calloc(MAX_SCR_PROVIDERS, sizeof(void*)); this->register_scr(this, unixscr_init()); diff --git a/src/xine-engine/metronom.h b/src/xine-engine/metronom.h index ef432c9ea..368bed25e 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.9 2001/08/07 16:00:10 ehasenle Exp $ + * $Id: metronom.h,v 1.10 2001/08/25 07:12:16 guenter Exp $ * * metronom: general pts => virtual calculation/assoc * @@ -121,13 +121,12 @@ struct metronom_s { int32_t (*get_av_offset) (metronom_t *this); /* - * **************************************** - * master clock functions - * **************************************** + * system clock reference (SCR) functions */ /* * start metronom clock (no clock reset) + * at given pts */ void (*start_clock) (metronom_t *this, uint32_t pts); @@ -155,6 +154,14 @@ struct metronom_s { */ void (*adjust_clock) (metronom_t *this, uint32_t desired_pts); + + /* + * set clock speed + * for constants see xine_internal.h + */ + + int (*set_speed) (metronom_t *this, int speed); + /* * (un)register a System Clock Reference provider at the metronom */ @@ -207,13 +214,24 @@ struct metronom_s { metronom_t *metronom_init (int have_audio); +/* + * SCR plugins + */ + struct scr_plugin_s { int interface_version; int (*get_priority) (scr_plugin_t *this); - void (*set_speed) (scr_plugin_t *this, float pts_ps); + /* + * set/get clock speed + * + * for speed constants see xine_internal.h + * returns actual speed + */ + + int (*set_speed) (scr_plugin_t *this, int speed); void (*adjust) (scr_plugin_t *this, uint32_t vpts); diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c index 1e7b0a275..3760af606 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.47 2001/08/24 10:02:05 guenter Exp $ + * $Id: xine.c,v 1.48 2001/08/25 07:12:16 guenter Exp $ * * top-level xine functions * @@ -30,6 +30,7 @@ #include #include #include +#include #include #if defined (__linux__) #include @@ -74,46 +75,27 @@ void xine_stop (xine_t *this) { pthread_mutex_unlock (&this->xine_lock); return; } - - if(this->status == XINE_PAUSE) { - - printf ("xine_stop: stopping demuxer\n"); - - if(this->cur_demuxer_plugin) { - this->cur_demuxer_plugin->stop (this->cur_demuxer_plugin); - } - - if(this->cur_input_plugin) { - this->cur_input_plugin->stop(this->cur_input_plugin); - } - goto pause_done; + this->status = XINE_STOP; + printf ("xine_stop: stopping demuxer\n"); + + if(this->cur_demuxer_plugin) { + this->cur_demuxer_plugin->stop (this->cur_demuxer_plugin); + this->cur_demuxer_plugin = NULL; } - else { - - printf ("xine_stop: closing demuxer\n"); - - if(this->cur_demuxer_plugin) { - this->cur_demuxer_plugin->close (this->cur_demuxer_plugin); - this->cur_demuxer_plugin = NULL; - } - - printf ("xine_stop: closing input\n"); - - if(this->cur_input_plugin) { - this->cur_input_plugin->close(this->cur_input_plugin); - /* - * If we set it to NULL, xine_eject() will not work after - * a xine_stop() call. - * - * this->cur_input_plugin = NULL; - */ - } + + printf ("xine_stop: closing input\n"); + + if(this->cur_input_plugin) { + this->cur_input_plugin->close(this->cur_input_plugin); + /* + * If we set it to NULL, xine_eject() will not work after + * a xine_stop() call. + * + * this->cur_input_plugin = NULL; + */ } - - this->status = XINE_STOP; - pause_done: printf ("xine_stop: done\n"); pthread_mutex_unlock (&this->xine_lock); @@ -270,52 +252,25 @@ void xine_play (xine_t *this, char *MRL, int spos) { pthread_mutex_lock (&this->xine_lock); - switch (this->status) { - case XINE_PAUSE: + if (this->status != XINE_STOP) { + + this->metronom->set_speed (this->metronom, SPEED_NORMAL); + this->audio_mute = 0; + pthread_mutex_unlock (&this->xine_lock); - xine_pause(this); return; - break; + } - case XINE_STOP: - xine_play_internal (this, MRL, spos, (off_t) 0); - break; + xine_play_internal (this, MRL, spos, (off_t) 0); - default: - printf ("xine_play: error, xine is not paused/stopped\n"); - } pthread_mutex_unlock (&this->xine_lock); } -void xine_seek (xine_t *this, char *MRL, int spos) { - - pthread_mutex_lock (&this->xine_lock); +void xine_seek (xine_t *this, char *mrl, int pos) { - printf ("xine_seek\n"); - - switch (this->status) { - case XINE_PLAY: - case XINE_STOP: - case XINE_PAUSE: - this->status = XINE_SEEK; - - if(this->cur_demuxer_plugin) { - this->cur_demuxer_plugin->stop (this->cur_demuxer_plugin); - } - - if(this->cur_input_plugin) { - this->cur_input_plugin->stop(this->cur_input_plugin); - } - - this->status = XINE_STOP; - xine_play_internal (this, MRL, spos, (off_t)0); - break; - - default: - printf ("xine_play: error, unhandled status %d\n", this->status); - } + xine_stop (this); + xine_play (this, mrl, pos); - pthread_mutex_unlock (&this->xine_lock); } int xine_eject (xine_t *this) { @@ -385,30 +340,25 @@ void xine_pause (xine_t *this) { printf ("xine_pause\n"); - if (this->status == XINE_PAUSE) { + if (this->status != XINE_PLAY) { + printf ("xine: error, pause called when not in playback mode\n"); - xprintf (VERBOSE, "xine play %s from %Ld\n", - this->cur_mrl, this->cur_input_pos); + return; + } - this->status = XINE_STOP; - xine_play_internal (this, this->cur_mrl, 0, this->cur_input_pos); - /* this->mnPausePos = 0; */ - } else if (this->status == XINE_PLAY) { + if (this->paused) { - pthread_mutex_unlock (&this->xine_lock); + this->metronom->set_speed (this->metronom, SPEED_NORMAL); + this->audio_mute = 0; + this->paused = 0; - printf ("pausing at %Ld\n", this->cur_input_pos); + } else { - /* - * xine_stop() will not change the status is - * previous status is XINE_PAUSE. - */ - this->status = XINE_PAUSE; + this->metronom->set_speed (this->metronom, SPEED_PAUSE); + this->paused = 1; + this->audio_mute = 2; - xine_stop (this); - - pthread_mutex_lock (&this->xine_lock); } pthread_mutex_unlock (&this->xine_lock); @@ -441,6 +391,11 @@ static void event_handler(xine_t *xine, event_t *event, void *data) { } } break; + case XINE_SPU_EVENT: + if (xine->cur_spu_decoder_plugin) + xine->cur_spu_decoder_plugin->event(xine->cur_spu_decoder_plugin, + (spu_event_t*) event); + break; } } @@ -467,11 +422,6 @@ xine_t *xine_init (vo_driver_t *vo, profiler_set_label (1, "audio decoder/output "); profiler_set_label (2, "video output "); - /* - * init event listeners - */ - this->num_event_listeners = 0; /* Initially there are none */ - /* * init lock */ @@ -507,14 +457,17 @@ xine_t *xine_init (vo_driver_t *vo, this->video_out = vo_new_instance (vo, this->metronom); video_decoder_init (this); - if(ao) { + if(ao) this->audio_out = ao_new_instance (ao, this->metronom, config); -// this->audio_out = ao; -// this->audio_out->connect (this->audio_out, this->metronom); - } + audio_decoder_init (this); printf("xine_init returning\n"); + /* + * init event listeners + */ + this->num_event_listeners = 0; /* Initially there are none */ + if((xine_register_event_listener(this, event_handler)) < 1) { fprintf(stderr, "xine_register_event_listener() failed.\n"); } @@ -622,3 +575,39 @@ int xine_check_version(int major, int minor, int sub) { return 0; } + +/* + * manually adjust a/v sync + */ + +void xine_set_av_offset (xine_t *this, int offset_pts) { + this->metronom->set_av_offset (this->metronom, offset_pts); +} + +int xine_get_av_offset (xine_t *this) { + return this->metronom->get_av_offset (this->metronom); +} + +/* + * trick play + */ + +void xine_set_speed (xine_t *this, int speed) { + + pthread_mutex_lock (&this->xine_lock); + + printf ("xine_set_speed %d\n", speed); + + this->metronom->set_speed (this->metronom, speed); + + this->audio_mute = speed != SPEED_NORMAL; + this->paused = speed == SPEED_PAUSE; + this->speed = speed; + + pthread_mutex_unlock (&this->xine_lock); +} + + +int xine_get_speed (xine_t *this) { + return this->speed; +} diff --git a/src/xine-engine/xine_internal.h b/src/xine-engine/xine_internal.h index 39ede9b61..d8727e172 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.40 2001/08/23 21:40:05 guenter Exp $ + * $Id: xine_internal.h,v 1.41 2001/08/25 07:12:16 guenter Exp $ * */ @@ -119,9 +119,7 @@ typedef void (*gui_stream_end_cb_t)(int nStatus); #define XINE_STOP 0 #define XINE_PLAY 1 -#define XINE_PAUSE 2 -#define XINE_SEEK 3 -#define XINE_QUIT 4 +#define XINE_QUIT 2 typedef struct xine_s xine_t; @@ -145,6 +143,7 @@ struct xine_s { int demux_strategy; int status; + int speed; off_t cur_input_pos; char cur_mrl[1024]; @@ -166,6 +165,7 @@ struct xine_s { video_decoder_t *video_decoder_plugins[DECODER_PLUGIN_MAX]; video_decoder_t *cur_video_decoder_plugin; int video_finished; + int paused; ao_instance_t *audio_out; fifo_buffer_t *audio_fifo; @@ -176,6 +176,7 @@ struct xine_s { uint32_t audio_track_map[50]; int audio_track_map_entries; int audio_finished; + int audio_mute; gui_stream_end_cb_t stream_end_cb; gui_get_next_mrl_cb_t get_next_mrl_cb; @@ -233,6 +234,28 @@ void xine_seek (xine_t *this, char *MRL, int pos); */ void xine_pause (xine_t *this); +/* + * set/get playback speed + * + * constants see below + */ + +void xine_set_speed (xine_t *this, int speed); +int xine_get_speed (xine_t *this); + +#define SPEED_PAUSE 0 +#define SPEED_SLOW_4 1 +#define SPEED_SLOW_2 2 +#define SPEED_NORMAL 4 +#define SPEED_FAST_2 8 +#define SPEED_FAST_4 16 + +/* + * manually adjust a/v sync + */ + +void xine_set_av_offset (xine_t *this, int offset_pts); +int xine_get_av_offset (xine_t *this); /* * stop playing -- cgit v1.2.3