diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/audio_out/audio_alsa05_out.c | 58 | ||||
-rw-r--r-- | src/audio_out/audio_alsa_out.c | 31 | ||||
-rw-r--r-- | src/audio_out/audio_oss_out.c | 39 | ||||
-rw-r--r-- | src/audio_out/audio_sun_out.c | 30 | ||||
-rw-r--r-- | src/demuxers/demux_mpeg_block.c | 35 | ||||
-rw-r--r-- | src/libmpg123/layer3.c | 24 | ||||
-rw-r--r-- | src/xine-engine/audio_decoder.c | 7 | ||||
-rw-r--r-- | src/xine-engine/audio_out.h | 14 | ||||
-rw-r--r-- | src/xine-engine/metronom.c | 259 | ||||
-rw-r--r-- | src/xine-engine/metronom.h | 40 | ||||
-rw-r--r-- | src/xine-engine/video_decoder.c | 24 | ||||
-rw-r--r-- | src/xine-engine/xine.c | 20 |
12 files changed, 378 insertions, 203 deletions
diff --git a/src/audio_out/audio_alsa05_out.c b/src/audio_out/audio_alsa05_out.c index 88e2f17b0..9e3fd121f 100644 --- a/src/audio_out/audio_alsa05_out.c +++ b/src/audio_out/audio_alsa05_out.c @@ -24,7 +24,7 @@ * for the SPDIF AC3 sync part * (c) 2000 Andy Lo A Foe <andy@alsaplayer.org> * - * $Id: audio_alsa05_out.c,v 1.2 2001/06/06 19:34:23 f1rmb Exp $ + * $Id: audio_alsa05_out.c,v 1.3 2001/06/23 19:45:47 guenter Exp $ */ /* required for swab() */ @@ -57,6 +57,7 @@ #define GAP_TOLERANCE 15000 #define MAX_MASTER_CLOCK_DIV 5000 +#define MAX_GAP 90000 extern uint32_t xine_debug; @@ -77,6 +78,8 @@ typedef struct _audio_alsa_globals { int audio_step; /* pts per 32 768 samples (sample = #bytes/2) */ int32_t bytes_per_kpts; /* bytes per 1024/90000 sec */ + uint32_t last_audio_vpts; + int16_t *zero_space; int audio_started; @@ -100,8 +103,11 @@ typedef struct _audio_alsa_globals { } audio_alsa_globals_t; +/* FIXME : global variables are not allowed in plugins */ + static audio_alsa_globals_t gAudioALSA; + /* ------------------------------------------------------------------------- */ /* * @@ -203,13 +209,13 @@ static int ao_open(ao_functions_t *this,uint32_t bits, uint32_t rate, int ao_mod if(!rate) return 0; - if(gAudioALSA.front_handle != NULL) { + if(gAudioALSA.front_handle != NULL) { if(rate == gAudioALSA.input_sample_rate) return 1; - + snd_pcm_close(gAudioALSA.front_handle); - } + } gAudioALSA.input_sample_rate = rate; gAudioALSA.bytes_in_buffer = 0; @@ -218,6 +224,7 @@ static int ao_open(ao_functions_t *this,uint32_t bits, uint32_t rate, int ao_mod gAudioALSA.sync_bytes_in_buffer = 0; gAudioALSA.audio_started = 0; gAudioALSA.direction = SND_PCM_CHANNEL_PLAYBACK; + gAudioALSA.last_audio_vpts = 0; if (ao_mode == AO_CAP_MODE_AC3) { gAudioALSA.pcm_default_device = 2; @@ -233,7 +240,7 @@ static int ao_open(ao_functions_t *this,uint32_t bits, uint32_t rate, int ao_mod gAudioALSA.pcm_default_card, gAudioALSA.pcm_default_device, subdevice, direction -// | SND_PCM_OPEN_NONBLOCK)) < 0) { + /* | SND_PCM_OPEN_NONBLOCK)) < 0) { */ )) < 0) { perr("snd_pcm_open_subdevice() failed: %s\n", snd_strerror(err)); return 0; @@ -310,8 +317,10 @@ static int ao_open(ao_functions_t *this,uint32_t bits, uint32_t rate, int ao_mod pcm_chan_params.channel = gAudioALSA.direction; pcm_chan_params.start_mode = SND_PCM_START_FULL; - //pcm_chan_params.start_mode = SND_PCM_START_DATA; - //pcm_chan_params.stop_mode = SND_PCM_STOP_STOP; + /* + pcm_chan_params.start_mode = SND_PCM_START_DATA; + pcm_chan_params.stop_mode = SND_PCM_STOP_STOP; + */ pcm_chan_params.stop_mode = SND_PCM_STOP_ROLLOVER; gAudioALSA.start_mode = pcm_chan_params.start_mode; @@ -360,8 +369,12 @@ static int ao_open(ao_functions_t *this,uint32_t bits, uint32_t rate, int ao_mod * */ static void ao_fill_gap (uint32_t pts_len) { - int num_bytes = pts_len * gAudioALSA.bytes_per_kpts / 1024; - + int num_bytes; + + if (pts_len > MAX_GAP) + pts_len = MAX_GAP; + + num_bytes = pts_len * gAudioALSA.bytes_per_kpts / 1024; num_bytes = (num_bytes / 4) * 4; gAudioALSA.bytes_in_buffer += num_bytes; @@ -464,8 +477,8 @@ return; /* * */ -static void ao_put_samples(ao_functions_t *this,int16_t* output_samples, - uint32_t num_samples, uint32_t pts_) { +static int ao_put_samples(ao_functions_t *this,int16_t* output_samples, + uint32_t num_samples, uint32_t pts_) { uint32_t vpts; uint32_t audio_vpts; uint32_t master_vpts; @@ -480,7 +493,7 @@ static void ao_put_samples(ao_functions_t *this,int16_t* output_samples, num_samples, pts_, gAudioALSA.bytes_in_buffer); if (gAudioALSA.front_handle == NULL) - return; + return 1; // if(gAudioALSA.frag_size != num_samples) { // alsa_set_frag(num_samples, 6); @@ -488,6 +501,14 @@ static void ao_put_samples(ao_functions_t *this,int16_t* output_samples, vpts = gAudioALSA.metronom->got_audio_samples (gAudioALSA.metronom,pts_, num_samples); + if (vpts<gAudioALSA.last_audio_vpts) { + /* reject this */ + + return 1; + } + + gAudioALSA.last_audio_vpts = vpts; + /* * check if these samples "fit" in the audio output buffer * or do we have an audio "gap" here? @@ -499,7 +520,16 @@ static void ao_put_samples(ao_functions_t *this,int16_t* output_samples, "last_vpts=%d\n", num_samples, vpts, gAudioALSA.last_vpts); if (gap > GAP_TOLERANCE) { - // ao_fill_gap (gap); + + /* FIXME : sync wont work without this + ao_fill_gap (gap); + */ + /* keep xine responsive */ + /* + if (gap>MAX_GAP) + return 0; + */ + } else if (gap < -GAP_TOLERANCE) { bDropPackage = 1; @@ -636,6 +666,8 @@ static void ao_put_samples(ao_functions_t *this,int16_t* output_samples, gAudioALSA.last_vpts = vpts + num_samples * 90000 / gAudioALSA.input_sample_rate ; + + return 1; } /* ------------------------------------------------------------------------- */ diff --git a/src/audio_out/audio_alsa_out.c b/src/audio_out/audio_alsa_out.c index 9ec9b8d43..fca95f20d 100644 --- a/src/audio_out/audio_alsa_out.c +++ b/src/audio_out/audio_alsa_out.c @@ -24,7 +24,7 @@ * (c) 2001 James Courtier-Dutton <James@superbug.demon.co.uk> * * - * $Id: audio_alsa_out.c,v 1.9 2001/06/11 19:37:53 joachim_koenig Exp $ + * $Id: audio_alsa_out.c,v 1.10 2001/06/23 19:45:47 guenter Exp $ */ #ifdef HAVE_CONFIG_H @@ -79,6 +79,7 @@ #define GAP_TOLERANCE 15000 #define MAX_MASTER_CLOCK_DIV 5000 +#define MAX_GAP 90000 typedef struct alsa_functions_s { @@ -357,7 +358,12 @@ static uint32_t ao_get_current_vpts (alsa_functions_t *this) static void ao_fill_gap (alsa_functions_t *this, uint32_t pts_len) { snd_pcm_sframes_t res; - int num_frames = (double)pts_len * (double)this->input_sample_rate / (double)this->pts_per_second; + int num_frames; + + if (pts_len > MAX_GAP) + pts_len = MAX_GAP; + + num_frames = (double)pts_len * (double)this->input_sample_rate / (double)this->pts_per_second; num_frames = (num_frames / 4) * 4; this->frames_in_buffer += num_frames; while (num_frames>0) { @@ -445,9 +451,9 @@ void write_pause_burst(alsa_functions_t *this,int error) -static void ao_write_audio_data(ao_functions_t *this_gen, - int16_t* output_samples, uint32_t num_samples, - uint32_t pts_) +static int ao_write_audio_data(ao_functions_t *this_gen, + int16_t* output_samples, uint32_t num_samples, + uint32_t pts_) { alsa_functions_t *this = (alsa_functions_t *) this_gen; @@ -466,6 +472,13 @@ static void ao_write_audio_data(ao_functions_t *this_gen, } vpts = this->metronom->got_audio_samples (this->metronom, pts_, num_samples); + + if (vpts<this->last_audio_vpts) { + /* reject this */ + + return 1; + } + /* * check if these samples "fit" in the audio output buffer * or do we have an audio "gap" here? @@ -475,6 +488,12 @@ static void ao_write_audio_data(ao_functions_t *this_gen, #if 0 if (gap>GAP_TOLERANCE) { ao_fill_gap (this, gap); + + /* keep xine responsive */ + + if (gap>MAX_GAP) + return 0; + } else if (gap<-GAP_TOLERANCE) { bDropPackage = 1; } @@ -567,6 +586,8 @@ static void ao_write_audio_data(ao_functions_t *this_gen, } this->last_vpts = vpts + num_samples * this->pts_per_second / this->input_sample_rate ; + + return 1; } diff --git a/src/audio_out/audio_oss_out.c b/src/audio_out/audio_oss_out.c index 4a38f51af..19c76e066 100644 --- a/src/audio_out/audio_oss_out.c +++ b/src/audio_out/audio_oss_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: audio_oss_out.c,v 1.14 2001/06/16 19:58:31 guenter Exp $ + * $Id: audio_oss_out.c,v 1.15 2001/06/23 19:45:47 guenter Exp $ */ /* required for swab() */ @@ -75,6 +75,7 @@ #define AUDIO_FRAGMENT_SIZE 8192 #define GAP_TOLERANCE 5000 +#define MAX_GAP 90000 #ifdef CONFIG_DEVFS_FS #define DSP_TEMPLATE "/dev/sound/dsp%d" @@ -105,7 +106,7 @@ typedef struct oss_functions_s { int16_t *zero_space; int audio_started; - + uint32_t last_audio_vpts; } oss_functions_t; /* @@ -136,6 +137,7 @@ static int ao_open(ao_functions_t *this_gen, this->input_sample_rate = rate; this->bytes_in_buffer = 0; this->audio_started = 0; + this->last_audio_vpts = 0; /* * open audio device @@ -239,9 +241,15 @@ static int ao_open(ao_functions_t *this_gen, static void ao_fill_gap (oss_functions_t *this, uint32_t pts_len) { - int num_bytes = pts_len * this->bytes_per_kpts / 1024; + int num_bytes ; + + if (pts_len > MAX_GAP) + pts_len = MAX_GAP; + num_bytes = pts_len * this->bytes_per_kpts / 1024; num_bytes = (num_bytes / (2*this->num_channels)) * (2*this->num_channels); - if(this->mode == AO_CAP_MODE_AC3) return; + + if(this->mode == AO_CAP_MODE_AC3) return; /* FIXME */ + printf ("audio_oss_out: inserting %d 0-bytes to fill a gap of %d pts\n",num_bytes, pts_len); this->bytes_in_buffer += num_bytes; @@ -257,9 +265,9 @@ static void ao_fill_gap (oss_functions_t *this, uint32_t pts_len) { } } -static void ao_write_audio_data(ao_functions_t *this_gen, - int16_t* output_samples, uint32_t num_samples, - uint32_t pts_) +static int ao_write_audio_data(ao_functions_t *this_gen, + int16_t* output_samples, uint32_t num_samples, + uint32_t pts_) { oss_functions_t *this = (oss_functions_t *) this_gen; @@ -278,6 +286,14 @@ static void ao_write_audio_data(ao_functions_t *this_gen, xprintf (VERBOSE|AUDIO, "audio_oss_out: got %d samples, vpts=%d\n", num_samples, vpts); + if (vpts<this->last_audio_vpts) { + /* reject this */ + + return 1; + } + + this->last_audio_vpts = vpts; + /* * where, in the timeline is the "end" of the audio buffer at the moment? */ @@ -310,6 +326,12 @@ static void ao_write_audio_data(ao_functions_t *this_gen, if (gap>GAP_TOLERANCE) { ao_fill_gap (this, gap); + + /* keep xine responsive */ + + if (gap>MAX_GAP) + return 0; + } else if (gap<-GAP_TOLERANCE) { bDropPackage = 1; } @@ -370,6 +392,9 @@ static void ao_write_audio_data(ao_functions_t *this_gen, } else { printf ("audio_oss_out: audio package (vpts = %d) dropped\n", vpts); } + + return 1; + } diff --git a/src/audio_out/audio_sun_out.c b/src/audio_out/audio_sun_out.c index 832ceb41f..b52a4d7af 100644 --- a/src/audio_out/audio_sun_out.c +++ b/src/audio_out/audio_sun_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: audio_sun_out.c,v 1.2 2001/06/22 10:45:03 jkeil Exp $ + * $Id: audio_sun_out.c,v 1.3 2001/06/23 19:45:47 guenter Exp $ */ #ifdef HAVE_CONFIG_H @@ -53,6 +53,7 @@ #endif #define GAP_TOLERANCE 5000 +#define MAX_GAP 90000 typedef struct sun_functions_s { @@ -163,7 +164,12 @@ static int ao_open(ao_functions_t *this_gen, static void ao_fill_gap (sun_functions_t *this, uint32_t pts_len) { - int num_bytes = pts_len * this->bytes_per_kpts / 1024; + int num_bytes; + + if (pts_len > MAX_GAP) + pts_len = MAX_GAP; + + num_bytes = pts_len * this->bytes_per_kpts / 1024; num_bytes = (num_bytes / (2*this->num_channels)) * (2*this->num_channels); if(this->mode == AO_CAP_MODE_AC3) return; printf ("audio_sun_out: inserting %d 0-bytes to fill a gap of %d pts\n",num_bytes, pts_len); @@ -181,9 +187,9 @@ static void ao_fill_gap (sun_functions_t *this, uint32_t pts_len) { } } -static void ao_write_audio_data(ao_functions_t *this_gen, - int16_t* output_samples, uint32_t num_samples, - uint32_t pts_) +static int ao_write_audio_data(ao_functions_t *this_gen, + int16_t* output_samples, uint32_t num_samples, + uint32_t pts_) { sun_functions_t *this = (sun_functions_t *) this_gen; @@ -199,6 +205,12 @@ static void ao_write_audio_data(ao_functions_t *this_gen, vpts = this->metronom->got_audio_samples (this->metronom, pts_, num_samples); + if (vpts<this->last_audio_vpts) { + /* reject this */ + + return 1; + } + xprintf (VERBOSE|AUDIO, "audio_sun_out: got %d samples, vpts=%d\n", num_samples, vpts); @@ -234,6 +246,12 @@ static void ao_write_audio_data(ao_functions_t *this_gen, if (gap>GAP_TOLERANCE) { ao_fill_gap (this, gap); + + /* keep xine responsive */ + + if (gap>MAX_GAP) + return 0; + } else if (gap<-GAP_TOLERANCE) { bDropPackage = 1; } @@ -302,6 +320,8 @@ static void ao_write_audio_data(ao_functions_t *this_gen, } else { printf ("audio_sun_out: audio package (vpts = %d) dropped\n", vpts); } + + return 1; } diff --git a/src/demuxers/demux_mpeg_block.c b/src/demuxers/demux_mpeg_block.c index 051017a1e..e35bc8f4b 100644 --- a/src/demuxers/demux_mpeg_block.c +++ b/src/demuxers/demux_mpeg_block.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: demux_mpeg_block.c,v 1.20 2001/06/17 23:17:40 f1rmb Exp $ + * $Id: demux_mpeg_block.c,v 1.21 2001/06/23 19:45:47 guenter Exp $ * * demultiplexer for mpeg 1/2 program streams * @@ -61,6 +61,9 @@ typedef struct demux_mpeg_block_s { gui_get_next_mrl_cb_t next_mrl_cb; gui_branched_cb_t branched_cb; + + uint8_t *scratch; + } demux_mpeg_block_t ; @@ -339,18 +342,20 @@ static void *demux_mpeg_block_loop (void *this_gen) { buf_element_t *buf = NULL; demux_mpeg_block_t *this = (demux_mpeg_block_t *) this_gen; - printf ("demux_mpeg_block: demux loop starting...\n"); + /* printf ("demux_mpeg_block: demux loop starting...\n"); */ this->send_end_buffers = 1; do { demux_mpeg_block_parse_pack(this, 0); - + } while (this->status == DEMUX_OK) ; + /* printf ("demux_mpeg_block: demux loop finished (status: %d)\n", this->status); + */ this->status = DEMUX_FINISHED; @@ -480,7 +485,6 @@ static int demux_mpeg_block_open(demux_plugin_t *this_gen, switch(stage) { case STAGE_BY_CONTENT: { - uint8_t buf[4096]; if((input->get_capabilities(input) & INPUT_CAP_SEEKABLE) != 0) { @@ -490,15 +494,17 @@ static int demux_mpeg_block_open(demux_plugin_t *this_gen, /* detect blocksize */ input->seek(input, 2048, SEEK_SET); - if (!input->read(input, buf, 4)) + if (!input->read(input, this->scratch, 4)) return DEMUX_CANNOT_HANDLE; - if(buf[0] || buf[1] || (buf[2] != 0x01) || (buf[3] != 0xba)) { + if (this->scratch[0] || this->scratch[1] + || (this->scratch[2] != 0x01) || (this->scratch[3] != 0xba)) { input->seek(input, 2324, SEEK_SET); - if (!input->read(input, buf, 4)) + if (!input->read(input, this->scratch, 4)) return DEMUX_CANNOT_HANDLE; - if(buf[0] || buf[1] || (buf[2] != 0x01) || (buf[3] != 0xba)) + if (this->scratch[0] || this->scratch[1] + || (this->scratch[2] != 0x01) || (this->scratch[3] != 0xba)) return DEMUX_CANNOT_HANDLE; this->blocksize = 2324; @@ -506,15 +512,16 @@ static int demux_mpeg_block_open(demux_plugin_t *this_gen, this->blocksize = 2048; } - /* make sure it's mpeg-2 */ - input->seek(input, 0, SEEK_SET); - if (input->read(input, buf, this->blocksize)) { + if (input->read(input, this->scratch, this->blocksize)) { - if(buf[0] || buf[1] || (buf[2] != 0x01) || (buf[3] != 0xba)) + if (this->scratch[0] || this->scratch[1] + || (this->scratch[2] != 0x01) || (this->scratch[3] != 0xba)) return DEMUX_CANNOT_HANDLE; - if ((buf[4]>>4) != 4) + /* if it's a file then make sure it's mpeg-2 */ + if ( !input->get_blocksize(input) + && ((this->scratch[4]>>4) != 4) ) return DEMUX_CANNOT_HANDLE; this->input = input; @@ -602,6 +609,8 @@ demux_plugin_t *init_demuxer_plugin(int iface, config_values_t *config) { this->demux_plugin.close = demux_mpeg_block_close; this->demux_plugin.get_status = demux_mpeg_block_get_status; this->demux_plugin.get_identifier = demux_mpeg_block_get_id; + + this->scratch = xmalloc_aligned (512, 4096); return (demux_plugin_t *) this; break; diff --git a/src/libmpg123/layer3.c b/src/libmpg123/layer3.c index 58c7d018a..88318370f 100644 --- a/src/libmpg123/layer3.c +++ b/src/libmpg123/layer3.c @@ -1600,18 +1600,20 @@ void do_layer3(mpgaudio_t *mp) } } - if ((!mp->is_output_initialized) || (mp->sample_rate_device != fr->sample_rate)) { - - if (mp->is_output_initialized) - mp->ao_output->close(mp->ao_output); + if (fr->sample_rate) { + if ((!mp->is_output_initialized) || (mp->sample_rate_device != fr->sample_rate)) { + + if (mp->is_output_initialized) + mp->ao_output->close(mp->ao_output); + + mp->ao_output->open (mp->ao_output, 16, fr->sample_rate, + stereo-1 ? AO_CAP_MODE_STEREO: AO_CAP_MODE_MONO); + mp->is_output_initialized = 1; + mp->sample_rate_device = fr->sample_rate; + } - mp->ao_output->open (mp->ao_output, 16, fr->sample_rate, - stereo-1 ? AO_CAP_MODE_STEREO: AO_CAP_MODE_MONO); - mp->is_output_initialized = 1; - mp->sample_rate_device = fr->sample_rate; + mp->ao_output->write_audio_data (mp->ao_output, (int16_t*)mp->osspace, num_bytes/(stereo-1 ? 4:2), + mp->pts); } - - mp->ao_output->write_audio_data (mp->ao_output, (int16_t*)mp->osspace, num_bytes/(stereo-1 ? 4:2), - mp->pts); mp->pts = 0; } diff --git a/src/xine-engine/audio_decoder.c b/src/xine-engine/audio_decoder.c index e7deee9ed..249f70777 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.21 2001/06/17 19:14:26 guenter Exp $ + * $Id: audio_decoder.c,v 1.22 2001/06/23 19:45:47 guenter Exp $ * * * functions that implement audio decoding @@ -72,10 +72,15 @@ void *audio_decoder_loop (void *this_gen) { this->audio_track_map[0] = 0; this->audio_track_map_entries = 0; + + this->metronom->audio_stream_start (this->metronom); break; case BUF_CONTROL_END: + + this->metronom->audio_stream_end (this->metronom); + if (this->cur_audio_decoder_plugin) { this->cur_audio_decoder_plugin->close (this->cur_audio_decoder_plugin); this->cur_audio_decoder_plugin = NULL; diff --git a/src/xine-engine/audio_out.h b/src/xine-engine/audio_out.h index 4c983bc0d..6b4e7a173 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.5 2001/06/18 10:49:31 guenter Exp $ + * $Id: audio_out.h,v 1.6 2001/06/23 19:45:47 guenter Exp $ */ #ifndef HAVE_AUDIO_OUT_H #define HAVE_AUDIO_OUT_H @@ -65,13 +65,17 @@ struct ao_functions_s { int (*open)(ao_functions_t *this, uint32_t bits, uint32_t rate, int mode); /* - * write audio data to output buffer - may block + * write audio data to output buffer * audio driver must sync sample playback with metronom + * return value: + * 1 => audio samples were processed ok + * 0 => audio samples were not yet processed, + * call write_audio_data with the _same_ samples again */ - void (*write_audio_data)(ao_functions_t *this, - int16_t* audio_data, uint32_t num_samples, - uint32_t pts); + int (*write_audio_data)(ao_functions_t *this, + int16_t* audio_data, uint32_t num_samples, + uint32_t pts); /* * this is called when the decoder no longer uses the audio diff --git a/src/xine-engine/metronom.c b/src/xine-engine/metronom.c index 224348c3a..89a0e0567 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.8 2001/06/04 17:13:36 guenter Exp $ + * $Id: metronom.c,v 1.9 2001/06/23 19:45:47 guenter Exp $ */ #ifdef HAVE_CONFIG_H @@ -38,35 +38,79 @@ #define MAX_PTS_TOLERANCE 5000 #define MAX_VIDEO_DELTA 1600 +#define MAX_AUDIO_DELTA 1600 #define AUDIO_SAMPLE_NUM 32768 -#define MAX_WRAP_TOLERANCE 90000 +#define WRAP_START_TIME 100000 +#define WRAP_TRESHOLD 30000 +#define MAX_NUM_WRAP_DIFF 100 -static void metronom_reset (metronom_t *this) { +static void metronom_video_stream_start (metronom_t *this) { pthread_mutex_lock (&this->lock); + printf ("video stream start...\n"); + this->pts_per_frame = 3000; this->video_vpts = 0; - this->audio_vpts = 0; this->video_pts_delta = 0; - this->audio_pts_delta = 0; this->last_video_pts = 0; this->num_video_vpts_guessed = 1; + + this->video_wrap_offset = 0; + this->wrap_diff_counter = 0; + + this->video_stream_running = 1; + this->video_stream_starting = 1; + + if (this->have_audio) { + while (!this->audio_stream_running) { + printf ("waiting for audio to start...\n"); + pthread_cond_wait (&this->audio_started, &this->lock); + } + } + pthread_cond_signal (&this->video_started); + + pthread_mutex_unlock (&this->lock); + + printf ("video stream start...done\n"); + + metronom_start_clock (this, 0); +} + +static void metronom_audio_stream_start (metronom_t *this) { + + pthread_mutex_lock (&this->lock); + + printf ("audio stream start...\n"); + + this->audio_vpts = 0; + + this->audio_pts_delta = 0; + this->num_audio_samples_guessed = 1; this->last_audio_pts = 0; - this->sync_pts = 0; - this->sync_vpts = 0; - - this->video_wrap_offset = 0; this->audio_wrap_offset = 0; + this->wrap_diff_counter = 0; + + this->audio_stream_running = 1; + this->audio_stream_starting = 1; - this->av_offset = 0; + while (!this->video_stream_running) { + printf ("waiting for video to start...\n"); + pthread_cond_wait (&this->video_started, &this->lock); + } + + pthread_cond_signal (&this->audio_started); pthread_mutex_unlock (&this->lock); + + printf ("audio stream start...done\n"); + + metronom_start_clock (this, 0); } static void metronom_set_video_rate (metronom_t *this, uint32_t pts_per_frame) { @@ -93,9 +137,9 @@ static void metronom_set_audio_rate (metronom_t *this, uint32_t pts_per_smpls) { } static uint32_t metronom_got_spu_packet (metronom_t *this, uint32_t pts) { - /* FIXME: Nasty hack */ + /* FIXME: not tested */ - return this->sync_pts; + return pts + this->video_wrap_offset; } static uint32_t metronom_got_video_frame (metronom_t *this, uint32_t pts) { @@ -104,81 +148,82 @@ static uint32_t metronom_got_video_frame (metronom_t *this, uint32_t pts) { pthread_mutex_lock (&this->lock); - /* pts = 0; */ - if (pts) { /* + * first video pts ? + */ + if (this->video_stream_starting) { + this->video_stream_starting = 0; + + this->video_wrap_offset = -1 * pts; + + printf ("metronom: first video pts => offset = %d\n", this->video_wrap_offset); + + } + + /* * did a wrap-around occur? */ - if ( (pts+this->video_wrap_offset+MAX_WRAP_TOLERANCE)<this->last_video_pts) { - this->video_wrap_offset = this->last_video_pts - pts + if ( ( (pts + WRAP_TRESHOLD) <this->last_video_pts) + && (pts<WRAP_START_TIME) ) { + + this->video_wrap_offset += this->last_video_pts - pts + this->num_video_vpts_guessed *(this->pts_per_frame + this->video_pts_delta); - + printf ("metronom: video pts wraparound detected, wrap_offset = %d\n", this->video_wrap_offset); + } + + /* + * audio and video wrap are not allowed to differ + * for too long + */ + + if ( !this->audio_stream_starting + && (this->video_wrap_offset != this->audio_wrap_offset)) { + this->wrap_diff_counter++; + if (this->wrap_diff_counter > MAX_NUM_WRAP_DIFF) { + + printf ("metronom: forcing video_wrap (%d) and audio wrap (%d)", + this->video_wrap_offset, this->audio_wrap_offset); + + if (this->video_wrap_offset > this->audio_wrap_offset) + this->audio_wrap_offset = this->video_wrap_offset; + else + this->video_wrap_offset = this->audio_wrap_offset; + + printf ("to %d\n", this->video_wrap_offset); + + this->wrap_diff_counter = 0; + } } - pts += this->video_wrap_offset; + vpts = pts + this->video_wrap_offset; /* * calc delta to compensate wrong framerates */ - if (this->last_video_vpts && (pts>this->last_video_pts)) { + if (this->last_video_pts && (pts>this->last_video_pts)) { int32_t vpts_diff; - uint32_t synced_vpts ; - int32_t diff; - diff = pts - this->last_video_pts; - synced_vpts = this->last_video_vpts + diff; - vpts_diff = synced_vpts - this->video_vpts; + vpts_diff = vpts - this->video_vpts; this->video_pts_delta += vpts_diff / (this->num_video_vpts_guessed); if (abs(this->video_pts_delta) >= MAX_VIDEO_DELTA) this->video_pts_delta = 0; - - this->num_video_vpts_guessed = 0; } - /* - * sync if necessary and possible - */ - - if (this->sync_vpts && (pts>this->sync_pts)) { - - int32_t vpts_diff; - uint32_t synced_vpts ; - int32_t diff; - - diff = pts - this->sync_pts; - synced_vpts = this->sync_vpts + diff; - vpts_diff = synced_vpts - this->video_vpts; - - xprintf (METRONOM | VERBOSE, "metronom: video calced vpts : %d <=> synced vpts : %d (diff: %d, delta: %d)\n", - this->video_vpts, synced_vpts, vpts_diff, this->video_pts_delta); - - if (abs(vpts_diff)>MAX_PTS_TOLERANCE) { - if ( synced_vpts>this->video_vpts ) { - this->video_vpts = synced_vpts; - } - } else { - xprintf (METRONOM | VERBOSE, "metronom: video tolerating diff\n"); - } - - } else - xprintf (METRONOM | VERBOSE, "metronom: video not synced on this one\n"); - - this->sync_pts = pts; - this->sync_vpts = this->video_vpts; - this->last_video_vpts = this->video_vpts; + this->num_video_vpts_guessed = 0; this->last_video_pts = pts; - } - - vpts = this->video_vpts; + this->video_vpts = vpts; + } else + vpts = this->video_vpts; + this->video_vpts += this->pts_per_frame + this->video_pts_delta; this->num_video_vpts_guessed++ ; @@ -203,57 +248,77 @@ static uint32_t metronom_got_audio_samples (metronom_t *this, uint32_t pts, uint int32_t diff; /* - * did a wrap-around occur? + * first audio pts ? */ + if (this->audio_stream_starting) { + this->audio_stream_starting = 0; + + this->audio_wrap_offset = -1 * pts; - if ((pts+this->audio_wrap_offset+MAX_WRAP_TOLERANCE)<this->last_audio_pts) { + printf ("metronom: first audio pts => offset = %d\n", this->audio_wrap_offset); + } - this->audio_wrap_offset = this->last_audio_pts - pts + /* + * did a wrap-around occur? + */ + if ( ( (pts + WRAP_TRESHOLD) < this->last_audio_pts ) + && (pts<WRAP_START_TIME) ) { + + this->audio_wrap_offset += this->last_audio_pts - pts + this->num_audio_samples_guessed *(this->audio_pts_delta + this->pts_per_smpls) / AUDIO_SAMPLE_NUM ; - + printf ("metronom: audio pts wraparound detected, wrap_offset = %d\n", this->audio_wrap_offset); - } - pts += this->audio_wrap_offset; + /* + * audio and video wrap are not allowed to differ + * for too long + */ - diff = pts - this->sync_pts; + if ( !this->video_stream_starting + && this->video_wrap_offset != this->audio_wrap_offset) { + this->wrap_diff_counter++; - if (this->sync_vpts && (pts>this->sync_pts)) { + if (this->wrap_diff_counter > MAX_NUM_WRAP_DIFF) { - int32_t vpts_diff; - uint32_t synced_vpts = this->sync_vpts + diff; + printf ("metronom: forcing video_wrap (%d) and audio wrap (%d)", + this->video_wrap_offset, this->audio_wrap_offset); - vpts_diff = synced_vpts - this->audio_vpts; + if (this->video_wrap_offset > this->audio_wrap_offset) + this->audio_wrap_offset = this->video_wrap_offset; + else + this->video_wrap_offset = this->audio_wrap_offset; - xprintf (METRONOM | VERBOSE, "metronom: audio calced vpts : %d <=> synced vpts : %d (diff: %d, delta: %d)\n", - this->audio_vpts, synced_vpts, vpts_diff, this->audio_pts_delta); - if (abs(vpts_diff)>5000) { + printf ("to %d\n", this->video_wrap_offset); - /* calc delta for wrong samplerates */ + this->wrap_diff_counter = 0; + } + } - this->audio_pts_delta += vpts_diff*AUDIO_SAMPLE_NUM / (this->num_audio_samples_guessed); - - if (abs(this->audio_pts_delta) >= 10000) - this->audio_pts_delta = 0; - - if (synced_vpts>this->audio_vpts) - this->audio_vpts = synced_vpts; - - } else - xprintf (METRONOM | VERBOSE, "metronom: audio tolerating diff\n"); + vpts = pts + this->audio_wrap_offset; + + /* + * calc delta to compensate wrong samplerates + */ + + if (this->last_audio_pts && (pts>this->last_audio_pts)) { + int32_t vpts_diff; - } else - xprintf (METRONOM | VERBOSE, "metronom: audio not synced on this one\n"); + vpts_diff = vpts - this->audio_vpts; + + this->audio_pts_delta += vpts_diff*AUDIO_SAMPLE_NUM / (this->num_audio_samples_guessed); + + if (abs(this->audio_pts_delta) >= MAX_AUDIO_DELTA) + this->audio_pts_delta = 0; + } - this->sync_pts = pts; - this->sync_vpts = this->audio_vpts; this->num_audio_samples_guessed = 0; this->last_audio_pts = pts; - } - - vpts = this->audio_vpts; + this->audio_vpts = vpts; + } else + vpts = this->audio_vpts; + this->audio_vpts += nsamples * (this->audio_pts_delta + this->pts_per_smpls) / AUDIO_SAMPLE_NUM; this->num_audio_samples_guessed += nsamples; @@ -360,11 +425,12 @@ static void metronom_adjust_clock(metronom_t *this, uint32_t desired_pts) pthread_mutex_unlock (&this->lock); } -metronom_t * metronom_init () { +metronom_t * metronom_init (int have_audio) { metronom_t *this = xmalloc (sizeof (metronom_t)); - this->reset = metronom_reset; + this->audio_stream_start= metronom_audio_stream_start; + this->video_stream_start= metronom_video_stream_start; this->set_video_rate = metronom_set_video_rate; this->get_video_rate = metronom_get_video_rate; this->set_audio_rate = metronom_set_audio_rate; @@ -380,8 +446,11 @@ metronom_t * metronom_init () { this->adjust_clock = metronom_adjust_clock; pthread_mutex_init (&this->lock, NULL); + pthread_cond_init (&this->video_started, NULL); + pthread_cond_init (&this->audio_started, NULL); - this->reset (this); + this->av_offset = 0; + this->have_audio = have_audio; return this; } diff --git a/src/xine-engine/metronom.h b/src/xine-engine/metronom.h index e051fc0da..5fae3eb9d 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.3 2001/05/01 21:55:23 guenter Exp $ + * $Id: metronom.h,v 1.4 2001/06/23 19:45:47 guenter Exp $ * * metronom: general pts => virtual calculation/assoc * @@ -41,11 +41,18 @@ typedef struct metronom_s metronom_t ; struct metronom_s { /* - * clear all cached data, reset current vpts ... called if new input - * file is reached + * this is called to tell metronom to prepare for a new video stream */ - - void (*reset) (metronom_t *this); + + void (*video_stream_start) (metronom_t *this); + void (*video_stream_end) (metronom_t *this); + + /* + * this is called to tell metronom to prepare for a new audio stream + */ + + void (*audio_stream_start) (metronom_t *this); + void (*audio_stream_end) (metronom_t *this); /* * called by video output driver to inform metronom about current framerate @@ -118,7 +125,7 @@ struct metronom_s { /* * start metronom clock (no clock reset) */ - void (*start_clock) (metronom_t *this, uint32_t pts); + void (*start_clock) (metronom_t *this, int32_t pts); /* @@ -156,15 +163,11 @@ struct metronom_s { uint32_t video_vpts; uint32_t audio_vpts; - uint32_t sync_pts; - uint32_t sync_vpts; - - uint32_t video_wrap_offset; - uint32_t audio_wrap_offset; + int32_t video_wrap_offset; + int32_t audio_wrap_offset; + int wrap_diff_counter; - /* video delta for wrong framerates */ uint32_t last_video_pts; - uint32_t last_video_vpts; int num_video_vpts_guessed; int32_t video_pts_delta; @@ -178,8 +181,17 @@ struct metronom_s { int stopped ; pthread_mutex_t lock; + + int have_audio; + int video_stream_starting; + int video_stream_running; + int audio_stream_starting; + int audio_stream_running; + pthread_cond_t video_started; + pthread_cond_t audio_started; + }; -metronom_t *metronom_init (); +metronom_t *metronom_init (int have_audio); #endif diff --git a/src/xine-engine/video_decoder.c b/src/xine-engine/video_decoder.c index c5a6eebe5..caf40bbae 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.25 2001/06/17 19:14:26 guenter Exp $ + * $Id: video_decoder.c,v 1.26 2001/06/23 19:45:47 guenter Exp $ * */ @@ -37,26 +37,14 @@ void *video_decoder_loop (void *this_gen) { while (running) { - /* printf ("video_decoder: getting buffer...\n"); */ + /* printf ("video_decoder: getting buffer...\n"); */ buf = this->video_fifo->get (this->video_fifo); if (buf->input_pos) this->cur_input_pos = buf->input_pos; - /* printf ("video_decoder: got buffer %d\n", buf->type); */ - - /* - * Call update status callback function if - * there is a video decoder initialized, like - * in mpeg1/2 playback. - */ - /* - if(this->cur_video_decoder_plugin != NULL) { - if(this->status == XINE_PLAY) - this->status_callback (this->status); - } - */ - + /* printf ("video_decoder: got buffer %d\n", buf->type); */ + switch (buf->type) { case BUF_CONTROL_START: @@ -69,6 +57,8 @@ void *video_decoder_loop (void *this_gen) { this->video_finished = 0; pthread_mutex_unlock (&this->xine_lock); + this->metronom->video_stream_start (this->metronom); + break; case BUF_VIDEO_MPEG: @@ -102,6 +92,8 @@ void *video_decoder_loop (void *this_gen) { case BUF_CONTROL_END: + this->metronom->video_stream_end (this->metronom); + if (this->cur_video_decoder_plugin) { this->cur_video_decoder_plugin->close (this->cur_video_decoder_plugin); this->cur_video_decoder_plugin = NULL; diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c index eb08a1e7b..542958083 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.29 2001/06/21 17:34:24 guenter Exp $ + * $Id: xine.c,v 1.30 2001/06/23 19:45:47 guenter Exp $ * * top-level xine functions * @@ -93,9 +93,6 @@ void xine_stop (xine_t *this) { this->spu_fifo->clear(this->spu_fifo); - this->metronom->stop_clock (this->metronom); - this->metronom->reset(this->metronom); - pthread_mutex_unlock (&this->xine_lock); } @@ -219,12 +216,6 @@ static void xine_play_internal (xine_t *this, char *mrl, this->cur_demuxer_plugin->get_identifier()); /* - * metronom - */ - - this->metronom->reset(this->metronom); - - /* * start demuxer */ @@ -244,11 +235,6 @@ static void xine_play_internal (xine_t *this, char *mrl, this->status = XINE_PLAY; strncpy (this->cur_mrl, mrl, 1024); - /* - * start clock - */ - - this->metronom->start_clock (this->metronom, 0); } void xine_play (xine_t *this, char *MRL, int spos) { @@ -389,7 +375,7 @@ xine_t *xine_init (vo_driver_t *vo, * create a metronom */ - this->metronom = metronom_init (); + this->metronom = metronom_init (ao != NULL); /* * load input and demuxer plugins @@ -440,8 +426,6 @@ void xine_select_audio_channel (xine_t *this, int channel) { this->audio_channel = channel; - /* this->metronom->reset(this->metronom); */ - pthread_mutex_unlock (&this->xine_lock); } |