summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuenter Bartsch <guenter@users.sourceforge.net>2001-06-23 19:45:47 +0000
committerGuenter Bartsch <guenter@users.sourceforge.net>2001-06-23 19:45:47 +0000
commitee8df4f4d8e2088da9dbc38e3230fad1de64908f (patch)
tree945c14e183c1c36bf91050e036efa67ae205e5e3
parent5e9ccc6f1f1689a317e574f48d3acedce3d11a40 (diff)
downloadxine-lib-ee8df4f4d8e2088da9dbc38e3230fad1de64908f.tar.gz
xine-lib-ee8df4f4d8e2088da9dbc38e3230fad1de64908f.tar.bz2
fixed race between metronom and xine engine, small audio plugin api change to improve responsiveness (unfinished), small demux_mpeg_block bugfix (alignment for DVD plugin)
CVS patchset: 218 CVS date: 2001/06/23 19:45:47
-rw-r--r--src/audio_out/audio_alsa05_out.c58
-rw-r--r--src/audio_out/audio_alsa_out.c31
-rw-r--r--src/audio_out/audio_oss_out.c39
-rw-r--r--src/audio_out/audio_sun_out.c30
-rw-r--r--src/demuxers/demux_mpeg_block.c35
-rw-r--r--src/libmpg123/layer3.c24
-rw-r--r--src/xine-engine/audio_decoder.c7
-rw-r--r--src/xine-engine/audio_out.h14
-rw-r--r--src/xine-engine/metronom.c259
-rw-r--r--src/xine-engine/metronom.h40
-rw-r--r--src/xine-engine/video_decoder.c24
-rw-r--r--src/xine-engine/xine.c20
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);
}