Update of /cvsroot/xine/xine-lib/src/xine-engine In directory usw-pr-cvs1:/tmp/cvs-serv28373/src/xine-engine Modified Files: audio_decoder.c audio_out.c audio_out.h buffer.h metronom.c metronom.h video_decoder.c video_out.c video_out.h Log Message: very unfinished scr discontinuity detection stuff, new software audio out buffer and thread Index: audio_decoder.c =================================================================== RCS file: /cvsroot/xine/xine-lib/src/xine-engine/audio_decoder.c,v retrieving revision 1.50 retrieving revision 1.51 diff -u -r1.50 -r1.51 --- audio_decoder.c 2001/10/22 01:23:08 1.50 +++ audio_decoder.c 2001/11/10 13:48:03 1.51 @@ -124,13 +124,24 @@ break; case BUF_VIDEO_FILL: - this->metronom->got_audio_still (this->metronom); break; case BUF_CONTROL_NOP: break; case BUF_CONTROL_DISCONTINUITY: + printf ("audio_decoder: BUF_CONTROL_DISCONTINUITY is deprecated\n"); + break; + + case BUF_CONTROL_AVSYNC_RESET: + printf ("audio_decoder: discontinuity ahead\n"); + + /* fixme ? */ + if (this->cur_audio_decoder_plugin) { + this->cur_audio_decoder_plugin->close (this->cur_audio_decoder_plugin); + this->cur_audio_decoder_plugin = NULL; + } + this->metronom->expect_audio_discontinuity (this->metronom); break; Index: audio_out.c =================================================================== RCS file: /cvsroot/xine/xine-lib/src/xine-engine/audio_out.c,v retrieving revision 1.23 retrieving revision 1.24 diff -u -r1.23 -r1.24 --- audio_out.c 2001/11/04 22:49:38 1.23 +++ audio_out.c 2001/11/10 13:48:03 1.24 @@ -1,7 +1,7 @@ /* * Copyright (C) 2000, 2001 the xine project * - * This file is part of xine, a unix video player. + * This file is part of xine, a free video player. * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -66,9 +66,14 @@ #include "metronom.h" #include "utils.h" -#define ZERO_BUF_SIZE 5000 +/* +#define AUDIO_OUT_LOG +*/ -#define MAX_GAP 90000 +#define NUM_AUDIO_BUFFERS 32 +#define AUDIO_BUF_SIZE 32768 + +#define ZERO_BUF_SIZE 5000 struct frmsize_s { @@ -119,59 +124,92 @@ { 640 ,{1280 ,1394 ,1920 } } }; -/* - * open the audio device for writing to - */ -static int ao_open(ao_instance_t *this, - uint32_t bits, uint32_t rate, int mode) -{ - int output_sample_rate; - if ((output_sample_rate=this->driver->open(this->driver,bits,(this->force_rate ? this->force_rate : rate),mode)) == 0) { - printf("audio_out: open failed!\n"); - return 0; - }; +struct audio_fifo_s { + audio_buffer_t *first; + audio_buffer_t *last; + int num_buffers; - printf("audio_out: output sample rate %d\n", output_sample_rate); + pthread_mutex_t mutex; + pthread_cond_t not_empty; +}; - this->mode = mode; - this->input_frame_rate = rate; - this->bits = bits; - this->audio_started = 0; - this->last_audio_vpts = 0; - this->output_frame_rate = output_sample_rate; +static audio_fifo_t *fifo_new () { - switch (this->resample_conf) { - case 1: /* force off */ - this->do_resample = 0; - break; - case 2: /* force on */ - this->do_resample = 1; - break; - default: /* AUTO */ - this->do_resample = this->output_frame_rate != this->input_frame_rate; + audio_fifo_t *fifo; + + fifo = (audio_fifo_t *) xmalloc (sizeof (audio_fifo_t)); + + if (!fifo) { + printf ("audio_out: out of memory!\n"); + return NULL; } - /* HACK: we do not have resample functions for 8-bit audio */ - if (this->bits==8) - this->do_resample = 0; + fifo->first = NULL; + fifo->last = NULL; + fifo->num_buffers = 0; + pthread_mutex_init (&fifo->mutex, NULL); + pthread_cond_init (&fifo->not_empty, NULL); - if (this->do_resample) - printf("audio_out: will resample audio from %d to %d\n", - this->input_frame_rate, this->output_frame_rate); + return fifo; +} - this->num_channels = this->driver->num_channels(this->driver); +static void fifo_append (audio_fifo_t *fifo, + audio_buffer_t *buf) { - this->frame_rate_factor = (double) this->output_frame_rate / (double) this->input_frame_rate; - this->audio_step = (uint32_t) 90000 * (uint32_t) 32768 / this->input_frame_rate; - this->frames_per_kpts = this->output_frame_rate * 1024 / 90000; - xprintf (VERBOSE|AUDIO, "audio_out : audio_step %d pts per 32768 frames\n", this->audio_step); + pthread_mutex_lock (&fifo->mutex); - this->metronom->set_audio_rate(this->metronom, this->audio_step); + buf->next = NULL; - return this->output_frame_rate; + if (!fifo->first) { + + fifo->first = buf; + fifo->last = buf; + fifo->num_buffers = 1; + + } else { + + fifo->last->next = buf; + fifo->last = buf; + fifo->num_buffers++; + + } + + pthread_cond_signal (&fifo->not_empty); + pthread_mutex_unlock (&fifo->mutex); } +static audio_buffer_t *fifo_remove (audio_fifo_t *fifo) { + + audio_buffer_t *buf; + + pthread_mutex_lock (&fifo->mutex); + + while (!fifo->first) { + pthread_cond_wait (&fifo->not_empty, &fifo->mutex); + } + + buf = fifo->first; + + if (buf) { + fifo->first = buf->next; + + if (!fifo->first) { + + fifo->last = NULL; + fifo->num_buffers = 0; + pthread_cond_init (&fifo->not_empty, NULL); + + } else + fifo->num_buffers--; + + } + + pthread_mutex_unlock (&fifo->mutex); + + return buf; +} + /* * This routine is currently not used, but I do not want to loose it. * I think "(c) 2001 Andy Lo A Foe <an...@al...>" originally added it @@ -216,10 +254,6 @@ static void ao_fill_gap (ao_instance_t *this, uint32_t pts_len) { int num_frames ; - xprintf (VERBOSE|AUDIO, "audio_out : fill_gap\n"); - - if (pts_len > MAX_GAP) - pts_len = MAX_GAP; num_frames = pts_len * this->frames_per_kpts / 1024; @@ -243,177 +277,297 @@ } -static int ao_write(ao_instance_t *this, - int16_t* output_frames, uint32_t num_frames, - uint32_t pts) -{ - uint32_t vpts, buffer_vpts; - int32_t gap; - int bDropPackage; - int delay; - int frame_size; - int fscod; - int frmsizecod; - uint8_t *data; - uint32_t cur_time; - - vpts = this->metronom->got_audio_samples (this->metronom, pts, num_frames); +static void *ao_loop (void *this_gen) { + + ao_instance_t *this = (ao_instance_t *) this_gen; + uint32_t hw_vpts; + audio_buffer_t *buf; + int32_t gap; + int delay; + int frame_size; + int fscod; + int frmsizecod; + uint8_t *data; + uint32_t cur_time; + int num_output_frames ; - xprintf (VERBOSE|AUDIO, "audio_out: got %d frames, vpts=%d pts=%d\n", - num_frames, vpts, pts); + this->audio_loop_running = 1; + + while ((this->audio_loop_running) || + (!this->audio_loop_running && this->out_fifo->first)) { - if (vpts<this->last_audio_vpts) { - /* reject this */ - xprintf (VERBOSE|AUDIO, "audio_out: rejected frame vpts=%d, last_audio_vpts=%d\n", vpts,this->last_audio_vpts) - return 1; - } +#ifdef AUDIO_OUT_LOG + printf ("audio_out: fifo_remove\n"); +#endif - this->last_audio_vpts = vpts; + buf = fifo_remove (this->out_fifo); - bDropPackage = 0; + if (!buf->num_frames) + break; - if (this->audio_started) delay = this->driver->delay(this->driver); - else - delay = 0; - /* - * where, in the timeline is the "end" of the audio buffer at the moment? - */ + /* + * where, in the timeline is the "end" of the + * hardware audio buffer at the moment? + */ - cur_time = this->metronom->get_current_time (this->metronom); - buffer_vpts = cur_time; - - /* External A52 decoder delay correction */ - if ((this->mode==AO_CAP_MODE_A52) || (this->mode==AO_CAP_MODE_AC5)) - delay+=10; + cur_time = this->metronom->get_current_time (this->metronom); + hw_vpts = cur_time; - buffer_vpts += delay * 1024 / this->frames_per_kpts; - - /* - * calculate gap: - */ - - gap = vpts - buffer_vpts; +#ifdef AUDIO_OUT_LOG + printf ("audio_out: current delay is %d, current time is %d\n", + delay, cur_time); +#endif + + /* External A52 decoder delay correction */ + if ((this->mode==AO_CAP_MODE_A52) || (this->mode==AO_CAP_MODE_AC5)) + delay+=10; - /* - printf ("vpts : %d buffer_vpts : %d gap %d\n", - vpts, buffer_vpts, gap); - */ + hw_vpts += delay * 1024 / this->frames_per_kpts; - if (gap>this->gap_tolerance) { - - - if (gap>15000) - ao_fill_gap (this, gap); - else { - printf ("audio_out: adjusting master clock %d -> %d\n", - cur_time, cur_time + gap); - this->metronom->adjust_clock (this->metronom, - cur_time + gap); - } + /* + * calculate gap: + */ - /* keep xine responsive */ + gap = buf->vpts - hw_vpts; - if (gap>MAX_GAP) - return 0; + /* + printf ("vpts : %d buffer_vpts : %d gap %d\n", + vpts, buffer_vpts, gap); + */ + + /* + * output audio data synced to master clock + */ + + if (gap < (-1 * this->gap_tolerance)) { + + /* drop package */ + + xprintf (VERBOSE|AUDIO, "audio_out: audio package (vpts = %d %d) dropped\n", + vpts, gap); + + } else { + + if (gap>this->gap_tolerance) { - } else if (gap < (-1 * this->gap_tolerance)) { - bDropPackage = 1; - xprintf (VERBOSE|AUDIO, "audio_out: audio package (vpts = %d %d)" - "dropped\n", vpts, gap); - } + if (gap>15000) + ao_fill_gap (this, gap); + else { + printf ("audio_out: adjusting master clock %d -> %d\n", + cur_time, cur_time + gap); + this->metronom->adjust_clock (this->metronom, + cur_time + gap); + } + + } + /* + * resample and output audio data + */ + + num_output_frames = (double) buf->num_frames * this->frame_rate_factor; + + if ((!this->do_resample) + && (this->mode != AO_CAP_MODE_A52) + && (this->mode != AO_CAP_MODE_AC5)) { + + this->driver->write (this->driver, buf->mem, + buf->num_frames ); + } else switch (this->mode) { + case AO_CAP_MODE_MONO: + audio_out_resample_mono (buf->mem, buf->num_frames, + this->frame_buffer, num_output_frames); + this->driver->write(this->driver, this->frame_buffer, num_output_frames); + break; + case AO_CAP_MODE_STEREO: + audio_out_resample_stereo (buf->mem, buf->num_frames, + this->frame_buffer, num_output_frames); + this->driver->write(this->driver, this->frame_buffer, num_output_frames); + break; + case AO_CAP_MODE_4CHANNEL: + audio_out_resample_4channel (buf->mem, buf->num_frames, + this->frame_buffer, num_output_frames); + this->driver->write(this->driver, this->frame_buffer, num_output_frames); + break; + case AO_CAP_MODE_5CHANNEL: + audio_out_resample_5channel (buf->mem, buf->num_frames, + this->frame_buffer, num_output_frames); + this->driver->write(this->driver, this->frame_buffer, num_output_frames); + break; + case AO_CAP_MODE_5_1CHANNEL: + audio_out_resample_6channel (buf->mem, buf->num_frames, + this->frame_buffer, num_output_frames); + this->driver->write(this->driver, this->frame_buffer, num_output_frames); + break; + case AO_CAP_MODE_A52: + + this->frame_buffer[0] = 0xf872; /* spdif syncword */ + this->frame_buffer[1] = 0x4e1f; /* ............. */ + this->frame_buffer[2] = 0x0001; /* AC3 data */ + + data = (uint8_t *)&buf->mem[1]; /* skip AC3 sync */ + fscod = (data[2] >> 6) & 0x3; + frmsizecod = data[2] & 0x3f; + frame_size = frmsizecod_tbl[frmsizecod].frm_size[fscod] << 4; + this->frame_buffer[3] = frame_size; + + /* ac3 seems to be swabbed data */ + swab(buf->mem,this->frame_buffer+4, buf->num_frames ); + this->driver->write(this->driver, this->frame_buffer, 1536); + + break; + case AO_CAP_MODE_AC5: + memset(this->frame_buffer,0xff,6144); + this->frame_buffer[0] = 0xf872; /* spdif syncword */ + this->frame_buffer[1] = 0x4e1f; /* ............. */ + this->frame_buffer[2] = 0x0001; /* */ + + this->frame_buffer[3] = 0x3ee0; + + /* ac3 seems to be swabbed data */ + swab(buf->mem,this->frame_buffer+4, 2014 ); + + this->driver->write(this->driver, this->frame_buffer, 1024); + + break; + + } + + } + + fifo_append (this->free_fifo, buf); + + } + + pthread_exit(NULL); + + return NULL; +} + +/* + * open the audio device for writing to, start audio output thread + */ + +static int ao_open(ao_instance_t *this, + uint32_t bits, uint32_t rate, int mode) { + + int output_sample_rate, err; + + if ((output_sample_rate=this->driver->open(this->driver,bits,(this->force_rate ? this->force_rate : rate),mode)) == 0) { + printf("audio_out: open failed!\n"); + return 0; + }; + + printf("audio_out: output sample rate %d\n", output_sample_rate); + + this->mode = mode; + this->input_frame_rate = rate; + this->bits = bits; + this->last_audio_vpts = 0; + this->output_frame_rate = output_sample_rate; + + switch (this->resample_conf) { + case 1: /* force off */ + this->do_resample = 0; + break; + case 2: /* force on */ + this->do_resample = 1; + break; + default: /* AUTO */ + this->do_resample = this->output_frame_rate != this->input_frame_rate; + } + + /* HACK: we do not have resample functions for 8-bit audio */ + if (this->bits==8) + this->do_resample = 0; + + if (this->do_resample) + printf("audio_out: will resample audio from %d to %d\n", + this->input_frame_rate, this->output_frame_rate); + + this->num_channels = this->driver->num_channels(this->driver); + + this->frame_rate_factor = (double) this->output_frame_rate / (double) this->input_frame_rate; + this->audio_step = (uint32_t) 90000 * (uint32_t) 32768 / this->input_frame_rate; + this->frames_per_kpts = this->output_frame_rate * 1024 / 90000; + xprintf (VERBOSE|AUDIO, "audio_out : audio_step %d pts per 32768 frames\n", this->audio_step); + + this->metronom->set_audio_rate(this->metronom, this->audio_step); + /* - * resample and output frames + * start output thread */ - if (!bDropPackage) { - int num_output_frames = (double) num_frames * this->frame_rate_factor; + if ((err = pthread_create (&this->audio_thread, + NULL, ao_loop, this)) != 0) { - if ((!this->do_resample) - && (this->mode != AO_CAP_MODE_A52) - && (this->mode != AO_CAP_MODE_AC5)) { - xprintf (VERBOSE|AUDIO, "audio_out: writing without resampling\n"); - this->driver->write (this->driver, output_frames, - num_frames ); - } else switch (this->mode) { - case AO_CAP_MODE_MONO: - audio_out_resample_mono (output_frames, num_frames, - this->frame_buffer, num_output_frames); - this->driver->write(this->driver, this->frame_buffer, num_output_frames); - break; - case AO_CAP_MODE_STEREO: - audio_out_resample_stereo (output_frames, num_frames, - this->frame_buffer, num_output_frames); - this->driver->write(this->driver, this->frame_buffer, num_output_frames); - break; - case AO_CAP_MODE_4CHANNEL: - audio_out_resample_4channel (output_frames, num_frames, - this->frame_buffer, num_output_frames); - this->driver->write(this->driver, this->frame_buffer, num_output_frames); - break; - case AO_CAP_MODE_5CHANNEL: - audio_out_resample_5channel (output_frames, num_frames, - this->frame_buffer, num_output_frames); - this->driver->write(this->driver, this->frame_buffer, num_output_frames); - break; - case AO_CAP_MODE_5_1CHANNEL: - audio_out_resample_6channel (output_frames, num_frames, - this->frame_buffer, num_output_frames); - this->driver->write(this->driver, this->frame_buffer, num_output_frames); - break; - case AO_CAP_MODE_A52: + /* FIXME: how does this happen ? */ - this->frame_buffer[0] = 0xf872; /* spdif syncword */ - this->frame_buffer[1] = 0x4e1f; /* ............. */ - this->frame_buffer[2] = 0x0001; /* AC3 data */ - - data = (uint8_t *)&output_frames[1]; /* skip AC3 sync */ - fscod = (data[2] >> 6) & 0x3; - frmsizecod = data[2] & 0x3f; - frame_size = frmsizecod_tbl[frmsizecod].frm_size[fscod] << 4; - this->frame_buffer[3] = frame_size; - - /* ac3 seems to be swabbed data */ - swab(output_frames,this->frame_buffer+4, num_frames ); - this->driver->write(this->driver, this->frame_buffer, 1536); + printf ("audio_out: can't create thread (%s)\n", strerror(err)); + printf ("audio_out: sorry, this should not happen. please restart xine.\n"); + exit(1); - break; - case AO_CAP_MODE_AC5: - memset(this->frame_buffer,0xff,6144); - this->frame_buffer[0] = 0xf872; /* spdif syncword */ - this->frame_buffer[1] = 0x4e1f; /* ............. */ - this->frame_buffer[2] = 0x0001; /* */ + } else + printf ("audio_out: thread created\n"); - this->frame_buffer[3] = 0x3ee0; - /* ac3 seems to be swabbed data */ - swab(output_frames,this->frame_buffer+4, 2014 ); - - this->driver->write(this->driver, this->frame_buffer, 1024); - - break; - } + return this->output_frame_rate; +} - xprintf (AUDIO|VERBOSE, "audio_out :audio package written\n"); +static audio_buffer_t *ao_get_buffer (ao_instance_t *this) { + return fifo_remove (this->free_fifo); +} - /* - * step values - */ +static void ao_put_buffer (ao_instance_t *this, audio_buffer_t *buf) { - this->audio_started = 1; + if (buf->num_frames == 0) { + fifo_append (this->free_fifo, buf); + return; } - return 1; + buf->vpts = this->metronom->got_audio_samples (this->metronom, buf->vpts, + buf->num_frames, buf->scr); + if ( buf->vpts<this->last_audio_vpts) { + + /* reject buffer */ + printf ("audio_out: rejected buffer vpts=%d, last_audio_vpts=%d\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; + + } } +static void ao_close(ao_instance_t *this) { -static void ao_close(ao_instance_t *this) -{ + audio_buffer_t *audio_buffer; + + printf ("audio_out: stopping thread...\n"); + + if (this->audio_loop_running) { + void *p; + + this->audio_loop_running = 0; + + audio_buffer = fifo_remove(this->free_fifo); + audio_buffer->num_frames = 0; + fifo_append (this->out_fifo, audio_buffer); + + pthread_join (this->audio_thread, &p); + } + + printf ("audio_out: thread stopped, closing driver\n"); + this->driver->close(this->driver); } @@ -441,6 +595,7 @@ config_values_t *config) { ao_instance_t *this; + int i; this = xmalloc (sizeof (ao_instance_t)) ; @@ -448,7 +603,8 @@ this->metronom = metronom; this->open = ao_open; - this->write = ao_write; + this->get_buffer = ao_get_buffer; + this->put_buffer = ao_put_buffer; this->close = ao_close; this->exit = ao_exit; this->get_capabilities = ao_get_capabilities; @@ -462,6 +618,25 @@ this->resample_conf = config->lookup_int (config, "audio_resample_mode", 0); this->force_rate = config->lookup_int (config, "audio_force_rate", 0); + /* + * pre-allocate memory for samples + */ + + this->free_fifo = fifo_new (); + this->out_fifo = fifo_new (); + + for (i=0; i<NUM_AUDIO_BUFFERS; i++) { + + audio_buffer_t *buf; + + buf = (audio_buffer_t *) malloc (sizeof (audio_buffer_t)); + buf->mem = malloc (AUDIO_BUF_SIZE); + buf->mem_size = AUDIO_BUF_SIZE; + + fifo_append (this->free_fifo, buf); + } + + return this; } Index: audio_out.h =================================================================== RCS file: /cvsroot/xine/xine-lib/src/xine-engine/audio_out.h,v retrieving revision 1.19 retrieving revision 1.20 diff -u -r1.19 -r1.20 --- audio_out.h 2001/11/04 22:49:38 1.19 +++ audio_out.h 2001/11/10 13:48:03 1.20 @@ -34,7 +34,7 @@ #endif -#define AUDIO_OUT_IFACE_VERSION 2 +#define AUDIO_OUT_IFACE_VERSION 3 /* * ao_driver_s contains the driver every audio output @@ -90,7 +90,7 @@ * call write_audio_data with the _same_ samples again */ int (*write)(ao_driver_t *this, - int16_t* audio_data, uint32_t num_samples); + int16_t* audio_data, uint32_t num_samples); /* * this is called when the decoder no longer uses the audio @@ -121,6 +121,22 @@ /* * ao_instance_s contains the instance every audio decoder talks to */ +typedef struct audio_fifo_s audio_fifo_t; + +typedef struct audio_buffer_s audio_buffer_t; + +struct audio_buffer_s { + + audio_buffer_t *next; + + int16_t *mem; + int mem_size; + int num_frames; + + uint32_t vpts; + uint32_t scr; +}; + typedef struct ao_instance_s ao_instance_t; struct ao_instance_s { @@ -141,17 +157,17 @@ uint32_t bits, uint32_t rate, int mode); /* - * 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 + * get a piece of memory for audio data + */ + + audio_buffer_t * (*get_buffer) (ao_instance_t *this); + + /* + * append a buffer filled with audio data to the audio fifo + * for output */ - int (*write)(ao_instance_t *this, - int16_t* audio_data, uint32_t num_frames, - uint32_t pts); + void (*put_buffer) (ao_instance_t *this, audio_buffer_t *buf); /* audio driver is no longer used by decoder => close */ void (*close) (ao_instance_t *self); @@ -172,7 +188,6 @@ int32_t output_frame_rate, input_frame_rate; double frame_rate_factor; uint32_t num_channels; - int audio_started; uint32_t last_audio_vpts; int resample_conf; int force_rate; /* force audio output rate to this value if non-zero */ @@ -180,6 +195,8 @@ int mode; int bits; int gap_tolerance; + audio_fifo_t *free_fifo; + audio_fifo_t *out_fifo; uint16_t *frame_buffer; int16_t *zero_space; }; Index: buffer.h =================================================================== RCS file: /cvsroot/xine/xine-lib/src/xine-engine/buffer.h,v retrieving revision 1.23 retrieving revision 1.24 diff -u -r1.23 -r1.24 --- buffer.h 2001/11/07 19:41:26 1.23 +++ buffer.h 2001/11/10 13:48:03 1.24 @@ -65,10 +65,11 @@ #define BUF_CONTROL_START 0x01000000 #define BUF_CONTROL_END 0x01010000 #define BUF_CONTROL_QUIT 0x01020000 -#define BUF_CONTROL_DISCONTINUITY 0x01030000 +#define BUF_CONTROL_DISCONTINUITY 0x01030000 /* deprecated */ #define BUF_CONTROL_NOP 0x01040000 #define BUF_CONTROL_AUDIO_CHANNEL 0x01050000 #define BUF_CONTROL_SPU_CHANNEL 0x01060000 +#define BUF_CONTROL_AVSYNC_RESET 0x01070000 /* video buffer types: (please keep in sync with buffer_types.c) */ @@ -136,7 +137,8 @@ uint32_t size ; /* size of _content_ */ uint32_t max_size; uint32_t type; - uint32_t PTS; + uint32_t PTS; /* presentation time stamp, used for a/v sync */ + uint32_t SCR; /* system clock reference, used for discont. detection */ off_t input_pos; /* remember where this buf came from in the input source */ int input_time;/* time offset in seconds from beginning of stream */ uint32_t decoder_info[4]; /* additional decoder flags and other dec-spec. stuff */ Index: metronom.c =================================================================== RCS file: /cvsroot/xine/xine-lib/src/xine-engine/metronom.c,v retrieving revision 1.32 retrieving revision 1.33 diff -u -r1.32 -r1.33 --- metronom.c 2001/10/24 22:23:10 1.32 +++ metronom.c 2001/11/10 13:48:03 1.33 @@ -39,16 +39,16 @@ #include "metronom.h" #include "utils.h" -#define MAX_PTS_TOLERANCE 5000 -#define MAX_VIDEO_DELTA 1600 -#define MAX_AUDIO_DELTA 1600 -#define AUDIO_SAMPLE_NUM 32768 -#define WRAP_START_TIME 100000 -#define WRAP_TRESHOLD 30000 -#define MAX_NUM_WRAP_DIFF 100 -#define MAX_SCR_PROVIDERS 10 -#define REALTIME_PTS 90000.0 -#define PREBUFFER_PTS_OFFSET 30000 +#define MAX_PTS_TOLERANCE 5000 +#define MAX_VIDEO_DELTA 1600 +#define MAX_AUDIO_DELTA 1600 +#define AUDIO_SAMPLE_NUM 32768 +#define WRAP_START_TIME 100000 +#define WRAP_TRESHOLD 30000 +#define SCR_DISCONTINUITY 60000 +#define MAX_NUM_WRAP_DIFF 100 +#define MAX_SCR_PROVIDERS 10 +#define PREBUFFER_PTS_OFFSET 30000 /* #define METRONOM_LOG @@ -228,7 +228,7 @@ /* * virtual pts calculation -*/ + */ static void metronom_video_stream_start (metronom_t *this) { @@ -249,14 +249,18 @@ this->video_pts_delta = 0; this->last_video_pts = 0; + this->last_video_scr = 0; this->num_video_vpts_guessed = 1; - this->video_wrap_offset = 0; + this->video_wrap_offset = PREBUFFER_PTS_OFFSET; this->wrap_diff_counter = 0; this->video_stream_running = 1; this->video_stream_starting = 1; + this->video_discontinuity = 0; + this->video_discontinuity_count = 0; + if (this->have_audio) { /*while (!this->audio_stream_running) {*/ if (!this->audio_stream_running) { @@ -317,13 +321,17 @@ this->num_audio_samples_guessed = 1; this->last_audio_pts = 0; + this->last_audio_scr = 0; - this->audio_wrap_offset = 0; + this->audio_wrap_offset = PREBUFFER_PTS_OFFSET; this->wrap_diff_counter = 0; this->audio_stream_running = 1; this->audio_stream_starting = 1; + this->audio_discontinuity = 0; + this->audio_discontinuity_count = 0; + /*while (!this->video_stream_running) { */ if (!this->video_stream_running) { printf ("metronom: waiting for video to start...\n"); @@ -385,7 +393,8 @@ } -static uint32_t metronom_got_spu_packet (metronom_t *this, uint32_t pts,uint32_t duration) { +static uint32_t metronom_got_spu_packet (metronom_t *this, uint32_t pts, + uint32_t duration, uint32_t scr) { if (pts) { this->spu_vpts=pts; } else { @@ -402,21 +411,37 @@ return pts + this->video_wrap_offset; } -static void metronom_expect_audio_discontinuity (metronom_t *this) { - - printf ("metronom: expecting audio discontinuity\n"); - - this->audio_discontinuity = 10; -} - static void metronom_expect_video_discontinuity (metronom_t *this) { - printf ("metronom: expecting video discontinuity\n"); + pthread_mutex_lock (&this->lock); + printf ("metronom: video discontinuity\n"); + this->video_discontinuity = 10; + + this->video_discontinuity_count++; + pthread_cond_signal (&this->video_discontinuity_reached); + + while ( this->audio_discontinuity_count < + this->video_discontinuity_count ) { + pthread_cond_wait (&this->audio_discontinuity_reached, &this->lock); + } + + if ( this->video_vpts < this->audio_vpts ) { + this->video_vpts = this->audio_vpts; + printf("metronom: video vpts adjusted to %d\n", this->video_vpts); + } + + this->num_video_vpts_guessed = 1; + this->last_video_pts = this->video_vpts - this->video_wrap_offset; + + printf ("metronom: video discontinuity => last_video_pts=%d, wrap_offset=%d, video_vpts=%d\n", + this->last_video_pts, this->video_wrap_offset, this->video_vpts); + + pthread_mutex_unlock (&this->lock); } -static uint32_t metronom_got_video_frame (metronom_t *this, uint32_t pts) { +static uint32_t metronom_got_video_frame (metronom_t *this, uint32_t pts, uint32_t scr) { uint32_t vpts; @@ -425,44 +450,27 @@ if (pts) { /* - * first video pts ? + * first video pts ? */ - if (this->video_stream_starting) { + if (this->video_stream_starting) this->video_stream_starting = 0; - this->video_wrap_offset = this->video_vpts + this->pts_per_frame - pts; - assert (this->video_pts_delta == 0); - - if (this->audio_wrap_offset) { - if (this->audio_wrap_offset>this->video_wrap_offset) - this->video_wrap_offset = this->audio_wrap_offset; - else - this->audio_wrap_offset = this->video_wrap_offset; - } - - printf ("metronom: first video pts => offset = %d\n", this->video_wrap_offset); - - } - /* - * did a wrap-around occur? + * discontinuity ? */ - if ( ( (pts + WRAP_TRESHOLD) <this->last_video_pts) - && (this->video_discontinuity || (pts<WRAP_START_TIME)) ) { - + if ( this->video_discontinuity ) { + this->video_discontinuity = 0; this->video_wrap_offset += this->last_video_pts - pts - + this->num_video_vpts_guessed *(this->pts_per_frame + this->video_pts_delta); + + 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); - } + printf ("metronom: video pts discontinuity, pts is %d, last_pts is %d, wrap_offset = %d\n", + pts, this->last_video_pts, this->video_wrap_offset); - /* don't expect discontinuities forever */ - if (this->video_discontinuity) - this->video_discontinuity--; + } /* * audio and video wrap are not allowed to differ @@ -492,22 +500,6 @@ vpts = pts + this->video_wrap_offset; /* - * jump into the future? - */ - if (this->video_discontinuity - && (vpts > (this->video_vpts + 10000))) { - - printf ("metronom: video jump into the future\n"); - - this->video_discontinuity = 0; - - this->video_wrap_offset += this->last_video_pts - pts - + this->num_video_vpts_guessed *(this->pts_per_frame + this->video_pts_delta); - - vpts = pts + this->video_wrap_offset; - } - - /* * calc delta to compensate wrong framerates */ @@ -540,24 +532,38 @@ return vpts + this->av_offset; } -static void metronom_got_audio_still (metronom_t *this) { +static void metronom_expect_audio_discontinuity (metronom_t *this) { pthread_mutex_lock (&this->lock); - - this->audio_vpts += this->pts_per_frame + this->video_pts_delta; - this->audio_wrap_offset = this->video_wrap_offset; - this->last_audio_pts = this->audio_vpts - this->audio_wrap_offset; - this->audio_stream_starting = 0; - -#ifdef METRONOM_LOG - printf ("metronom: got audio still, vpts = %d, wrap = %d\n", - this->audio_vpts, this->audio_wrap_offset); -#endif + + printf ("metronom: audio discontinuity\n"); + + this->audio_discontinuity = 10; + this->audio_discontinuity_count++; + pthread_cond_signal (&this->audio_discontinuity_reached); + + while ( this->audio_discontinuity_count > + this->video_discontinuity_count ) { + pthread_cond_wait (&this->video_discontinuity_reached, &this->lock); + } + + if ( this->audio_vpts < this->video_vpts ) { + this->audio_vpts = this->video_vpts; + printf("metronom: audio vpts adjusted to %d\n", this->audio_vpts); + } + + this->num_audio_samples_guessed = 1; + this->last_audio_pts = this->audio_vpts - this->audio_wrap_offset; + + printf ("metronom: audio discontinuity => last_audio_pts=%d, wrap_offset=%d, audio_vpts=%d\n", + this->last_audio_pts, this->audio_wrap_offset, this->audio_vpts); pthread_mutex_unlock (&this->lock); } + -static uint32_t metronom_got_audio_samples (metronom_t *this, uint32_t pts, uint32_t nsamples) { +static uint32_t metronom_got_audio_samples (metronom_t *this, uint32_t pts, + uint32_t nsamples, uint32_t scr) { uint32_t vpts; @@ -566,53 +572,40 @@ pthread_mutex_lock (&this->lock); + + this->last_audio_scr = scr; + if (pts) { /* * first audio pts ? */ - if (this->audio_stream_starting) { + if (this->audio_stream_starting) this->audio_stream_starting = 0; - this->audio_wrap_offset = this->audio_vpts + (nsamples * this->pts_per_smpls) / AUDIO_SAMPLE_NUM - pts; - assert (this->audio_pts_delta == 0); - - if (this->video_wrap_offset) { - if (this->audio_wrap_offset>this->video_wrap_offset) - this->video_wrap_offset = this->audio_wrap_offset; - else - this->audio_wrap_offset = this->video_wrap_offset; - } - - printf ("metronom: first audio pts => offset = %d\n", this->audio_wrap_offset); - } - /* - * did a wrap-around occur? + * discontinuity ? */ - if ( ( (pts + WRAP_TRESHOLD) < this->last_audio_pts ) - && (this->audio_discontinuity || (pts<WRAP_START_TIME)) ) { + + if ( this->audio_discontinuity ) { this->audio_discontinuity = 0; 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 ; + + 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); - } + printf ("metronom: audio pts discontinuity, pts is %d, last_pts is %d, wrap_offset = %d\n", + pts, this->last_audio_pts, this->audio_wrap_offset); - /* don't expect discontinuities forever */ - if (this->audio_discontinuity) - this->audio_discontinuity--; + } /* * audio and video wrap are not allowed to differ * for too long */ - if ( !this->video_stream_starting - && this->video_wrap_offset != this->audio_wrap_offset) { + if ( this->video_wrap_offset != this->audio_wrap_offset ) { this->wrap_diff_counter++; if (this->wrap_diff_counter > MAX_NUM_WRAP_DIFF) { @@ -634,22 +627,6 @@ vpts = pts + this->audio_wrap_offset; /* - * jump into the future? - */ - if (this->audio_discontinuity - && (vpts > (this->audio_vpts + 10000))) { - - printf ("metronom: video jump into the future\n"); - - this->audio_discontinuity = 0; - - 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 ; - - vpts = pts + this->audio_wrap_offset; - } - - /* * calc delta to compensate wrong samplerates */ @@ -710,7 +687,7 @@ } } if (select < 0) { - printf("panic: No scr provider found!\n"); + printf("metronom: panic - no scr provider found!\n"); return NULL; } return this->scr_list[select]; @@ -776,10 +753,10 @@ this->got_video_frame = metronom_got_video_frame; this->got_audio_samples = metronom_got_audio_samples; this->got_spu_packet = metronom_got_spu_packet; + this->expect_audio_discontinuity = metronom_expect_audio_discontinuity; + this->expect_video_discontinuity = metronom_expect_video_discontinuity; this->set_av_offset = metronom_set_av_offset; this->get_av_offset = metronom_get_av_offset; - this->expect_video_discontinuity = metronom_expect_video_discontinuity; - this->expect_audio_discontinuity = metronom_expect_audio_discontinuity; this->start_clock = metronom_start_clock; this->stop_clock = metronom_stop_clock; this->resume_clock = metronom_resume_clock; @@ -788,21 +765,22 @@ this->register_scr = metronom_register_scr; this->unregister_scr = metronom_unregister_scr; this->set_speed = metronom_set_speed; - this->got_audio_still = metronom_got_audio_still; this->scr_list = calloc(MAX_SCR_PROVIDERS, sizeof(void*)); this->register_scr(this, unixscr_init()); if ((err = pthread_create(&this->sync_thread, NULL, (void*(*)(void*)) metronom_sync_loop, this)) != 0) - fprintf(stderr, "metronom: cannot create sync thread (%s)\n", - strerror(err)); + printf("metronom: cannot create sync thread (%s)\n", + strerror(err)); pthread_mutex_init (&this->lock, NULL); pthread_cond_init (&this->video_started, NULL); pthread_cond_init (&this->audio_started, NULL); pthread_cond_init (&this->video_ended, NULL); pthread_cond_init (&this->audio_ended, NULL); + pthread_cond_init (&this->video_discontinuity_reached, NULL); + pthread_cond_init (&this->audio_discontinuity_reached, NULL); this->av_offset = 0; this->have_audio = have_audio; Index: metronom.h =================================================================== RCS file: /cvsroot/xine/xine-lib/src/xine-engine/metronom.h,v retrieving revision 1.12 retrieving revision 1.13 diff -u -r1.12 -r1.13 --- metronom.h 2001/10/18 18:50:53 1.12 +++ metronom.h 2001/11/10 13:48:03 1.13 @@ -83,55 +83,52 @@ * called by video output driver for *every* frame * * parameter pts: pts for frame if known, 0 otherwise + * scr: system clock reference, may be 0 or == pts if unknown * * return value: virtual pts for frame * */ - uint32_t (*got_video_frame) (metronom_t *this, uint32_t pts); + uint32_t (*got_video_frame) (metronom_t *this, uint32_t pts, uint32_t scr); /* * called by audio output driver whenever audio samples are delivered to it * * parameter pts : pts for audio data if known, 0 otherwise * nsamples : number of samples delivered + * scr : system clock reference, may be 0 or == pts if unknown * * return value: virtual pts for audio data * */ - uint32_t (*got_audio_samples) (metronom_t *this, uint32_t pts, uint32_t nsamples); + uint32_t (*got_audio_samples) (metronom_t *this, uint32_t pts, uint32_t nsamples, uint32_t scr); - /* - * inform metronom that there was a still image with no audio - */ - - void (*got_audio_still) (metronom_t *this); - /* * called by SPU decoder whenever a packet is delivered to it * * parameter pts : pts for SPU packet if known, 0 otherwise + * scr : system clock reference, may be 0 or == pts if unknown * * return value: virtual pts for SPU packet * */ - uint32_t (*got_spu_packet) (metronom_t *this, uint32_t pts, uint32_t duration); + uint32_t (*got_spu_packet) (metronom_t *this, uint32_t pts, uint32_t duration, + uint32_t scr); /* - * manually correct audio <-> video sync + * tell metronom about discontinuities */ - void (*set_av_offset) (metronom_t *this, int32_t pts); - - int32_t (*get_av_offset) (metronom_t *this); + void (*expect_audio_discontinuity) (metronom_t *this); + void (*expect_video_discontinuity) (metronom_t *this); /* - * tell metronom to expect a pts discontinuity + * manually correct audio <-> video sync */ + void (*set_av_offset) (metronom_t *this, int32_t pts); - void (*expect_audio_discontinuity) (metronom_t *this); - void (*expect_video_discontinuity) (metronom_t *this); + int32_t (*get_av_offset) (metronom_t *this); /* * system clock reference (SCR) functions @@ -199,10 +196,12 @@ int wrap_diff_counter; uint32_t last_video_pts; + uint32_t last_video_scr; int num_video_vpts_guessed; int32_t video_pts_delta; uint32_t last_audio_pts; + uint32_t last_audio_scr; int num_audio_samples_guessed; int32_t av_offset; @@ -219,7 +218,11 @@ int audio_stream_starting; int audio_stream_running; int video_discontinuity; + int video_discontinuity_count; int audio_discontinuity; + int audio_discontinuity_count; + pthread_cond_t video_discontinuity_reached; + pthread_cond_t audio_discontinuity_reached; pthread_cond_t video_started; pthread_cond_t audio_started; pthread_cond_t video_ended; Index: video_decoder.c =================================================================== RCS file: /cvsroot/xine/xine-lib/src/xine-engine/video_decoder.c,v retrieving revision 1.61 retrieving revision 1.62 diff -u -r1.61 -r1.62 --- video_decoder.c 2001/11/06 21:46:05 1.61 +++ video_decoder.c 2001/11/10 13:48:03 1.62 @@ -101,18 +101,9 @@ break; - case BUF_SPU_CLUT: - profiler_start_count (prof_spu_decode); - - spu_decoder = update_spu_decoder(this, buf->type); - - if (spu_decoder) - spu_decoder->decode_data (spu_decoder, buf); - - profiler_stop_count (prof_spu_decode); - break; - case BUF_SPU_SUBP_CONTROL: + case BUF_SPU_CLUT: + case BUF_SPU_PACKAGE: profiler_start_count (prof_spu_decode); spu_decoder = update_spu_decoder(this, buf->type); @@ -127,22 +118,6 @@ this->spu_channel = buf->decoder_info[0]; break; - case BUF_SPU_PACKAGE: - profiler_start_count (prof_spu_decode); - - /* now, decode this buffer if it's the right track */ -// if ( (buf->type & 0xFFFF)== this->spu_channel) { - - spu_decoder = update_spu_decoder (this, buf->type); - - if (spu_decoder) - spu_decoder->decode_data (spu_decoder, buf); - -// } - - profiler_stop_count (prof_spu_decode); - break; - case BUF_CONTROL_END: this->metronom->video_stream_end (this->metronom); @@ -185,9 +160,22 @@ break; case BUF_CONTROL_DISCONTINUITY: + printf ("video_decoder: BUF_CONTROL_DISCONTINUITY is deprecated\n"); + break; + + case BUF_CONTROL_AVSYNC_RESET: + printf ("video_decoder: discontinuity ahead\n"); + + /* fixme ? */ + if (this->cur_video_decoder_plugin) { + this->cur_video_decoder_plugin->close (this->cur_video_decoder_plugin); + this->cur_video_decoder_plugin = NULL; + } + this->metronom->expect_video_discontinuity (this->metronom); break; + case BUF_CONTROL_AUDIO_CHANNEL: case BUF_CONTROL_NOP: break; Index: video_out.c =================================================================== RCS file: /cvsroot/xine/xine-lib/src/xine-engine/video_out.c,v retrieving revision 1.51 retrieving revision 1.52 diff -u -r1.51 -r1.52 --- video_out.c 2001/10/21 13:14:08 1.51 +++ video_out.c 2001/11/10 13:48:03 1.52 @@ -346,11 +346,11 @@ pthread_attr_setscope(&pth_attrs, PTHREAD_SCOPE_SYSTEM); if((err = pthread_create (&this->video_thread, - &pth_attrs, video_out_loop, this)) != 0) - { - fprintf (stderr, "video_out: can't create thread (%s)\n", strerror(err)); - /* FIXME: why pthread_create fails? */ - fprintf (stderr, "Sorry, this should not happen. Please restart Xine.\n"); + &pth_attrs, video_out_loop, this)) != 0) { + + printf ("video_out: can't create thread (%s)\n", strerror(err)); + /* FIXME: how does this happen ? */ + printf ("video_out: sorry, this should not happen. please restart xine.\n"); exit(1); } else @@ -469,7 +469,7 @@ uint32_t pic_vpts ; int frames_to_skip; - pic_vpts = this->metronom->got_video_frame (this->metronom, img->PTS); + pic_vpts = this->metronom->got_video_frame (this->metronom, img->PTS, img->SCR); /* printf ("video_out: got image %d. vpts for picture is %d (pts was %d)\n", Index: video_out.h =================================================================== RCS file: /cvsroot/xine/xine-lib/src/xine-engine/video_out.h,v retrieving revision 1.26 retrieving revision 1.27 diff -u -r1.26 -r1.27 --- video_out.h 2001/11/10 06:20:39 1.26 +++ video_out.h 2001/11/10 13:48:03 1.27 @@ -60,6 +60,7 @@ struct vo_frame_s *next; uint32_t PTS; + uint32_t SCR; int bad_frame; /* e.g. frame skipped or based on skipped frame */ uint8_t *base[3]; |