diff options
Diffstat (limited to 'src/xine-engine')
-rw-r--r-- | src/xine-engine/audio_decoder.c | 17 | ||||
-rw-r--r-- | src/xine-engine/audio_out.c | 5 | ||||
-rw-r--r-- | src/xine-engine/audio_out.h | 11 | ||||
-rw-r--r-- | src/xine-engine/buffer.h | 15 | ||||
-rw-r--r-- | src/xine-engine/buffer_types.c | 9 | ||||
-rw-r--r-- | src/xine-engine/metronom.c | 523 | ||||
-rw-r--r-- | src/xine-engine/metronom.h | 108 | ||||
-rw-r--r-- | src/xine-engine/video_decoder.c | 23 | ||||
-rw-r--r-- | src/xine-engine/video_out.c | 985 | ||||
-rw-r--r-- | src/xine-engine/video_out.h | 98 | ||||
-rw-r--r-- | src/xine-engine/video_overlay.h | 38 | ||||
-rw-r--r-- | src/xine-engine/xine.c | 14 |
12 files changed, 771 insertions, 1075 deletions
diff --git a/src/xine-engine/audio_decoder.c b/src/xine-engine/audio_decoder.c index fa6a3582b..169919f2b 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.57 2001/12/11 15:30:06 miguelfreitas Exp $ + * $Id: audio_decoder.c,v 1.58 2002/02/09 07:13:24 guenter Exp $ * * * functions that implement audio decoding @@ -81,14 +81,12 @@ void *audio_decoder_loop (void *this_gen) { this->audio_finished = 0; pthread_mutex_unlock (&this->finished_lock); - this->metronom->audio_stream_start (this->metronom); + this->metronom->expect_audio_discontinuity (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; @@ -124,23 +122,12 @@ void *audio_decoder_loop (void *this_gen) { running = 0; break; - case BUF_VIDEO_FILL: - 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"); - if (this->cur_audio_decoder_plugin) { - this->cur_audio_decoder_plugin->reset (this->cur_audio_decoder_plugin); - } - this->metronom->expect_audio_discontinuity (this->metronom); break; diff --git a/src/xine-engine/audio_out.c b/src/xine-engine/audio_out.c index c1c099fe7..2eca26b8f 100644 --- a/src/xine-engine/audio_out.c +++ b/src/xine-engine/audio_out.c @@ -17,7 +17,7 @@ * along with self program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: audio_out.c,v 1.39 2001/12/24 12:36:19 miguelfreitas Exp $ + * $Id: audio_out.c,v 1.40 2002/02/09 07:13:24 guenter Exp $ * * 22-8-2001 James imported some useful AC3 sections from the previous alsa driver. * (c) 2001 Andy Lo A Foe <andy@alsaplayer.org> @@ -237,7 +237,6 @@ static void *ao_loop (void *this_gen) { audio_buffer_t *buf; int32_t gap; int delay; - uint8_t *data; uint32_t cur_time; int num_output_frames ; int paused_wait; @@ -474,7 +473,7 @@ static void ao_put_buffer (ao_instance_t *this, audio_buffer_t *buf) { if ( buf->vpts<this->last_audio_vpts) { /* reject buffer */ - printf ("audio_out: rejected buffer vpts=%d, last_audio_vpts=%d\n", + printf ("audio_out: rejected buffer vpts=%lld, last_audio_vpts=%lld\n", buf->vpts, this->last_audio_vpts); fifo_append (this->free_fifo, buf); diff --git a/src/xine-engine/audio_out.h b/src/xine-engine/audio_out.h index ab219a648..23e987560 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.22 2001/11/27 00:00:35 jcdutton Exp $ + * $Id: audio_out.h,v 1.23 2002/02/09 07:13:24 guenter Exp $ */ #ifndef HAVE_AUDIO_OUT_H #define HAVE_AUDIO_OUT_H @@ -31,6 +31,9 @@ extern "C" { #if defined(XINE_COMPILE) #include "metronom.h" #include "configfile.h" +#else +#include <xine/metronom.h> +#include <xine/configfile.h> #endif @@ -133,8 +136,8 @@ struct audio_buffer_s { int mem_size; int num_frames; - uint32_t vpts; - uint32_t scr; + int64_t vpts; + int64_t scr; uint32_t frame_header_count; uint32_t first_access_unit; }; @@ -191,7 +194,7 @@ struct ao_instance_s { int32_t output_frame_rate, input_frame_rate; double frame_rate_factor; uint32_t num_channels; - uint32_t last_audio_vpts; + int64_t last_audio_vpts; int resample_conf; int force_rate; /* force audio output rate to this value if non-zero */ int do_resample; diff --git a/src/xine-engine/buffer.h b/src/xine-engine/buffer.h index f63327e23..685faf347 100644 --- a/src/xine-engine/buffer.h +++ b/src/xine-engine/buffer.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: buffer.h,v 1.32 2002/01/15 17:30:51 miguelfreitas Exp $ + * $Id: buffer.h,v 1.33 2002/02/09 07:13:24 guenter Exp $ * * * contents: @@ -65,12 +65,10 @@ extern "C" { #define BUF_CONTROL_START 0x01000000 #define BUF_CONTROL_END 0x01010000 #define BUF_CONTROL_QUIT 0x01020000 -#define BUF_CONTROL_DISCONTINUITY 0x01030000 /* deprecated */ +#define BUF_CONTROL_DISCONTINUITY 0x01030000 /* former AVSYNC_RESET */ #define BUF_CONTROL_NOP 0x01040000 #define BUF_CONTROL_AUDIO_CHANNEL 0x01050000 #define BUF_CONTROL_SPU_CHANNEL 0x01060000 -#define BUF_CONTROL_AVSYNC_RESET 0x01070000 -#define BUF_CONTROL_FLUSH 0x01080000 /* video buffer types: (please keep in sync with buffer_types.c) */ @@ -90,7 +88,6 @@ extern "C" { #define BUF_VIDEO_ATIVCR2 0x020c0000 #define BUF_VIDEO_I263 0x020d0000 #define BUF_VIDEO_RV10 0x020e0000 -#define BUF_VIDEO_FILL 0x020f0000 #define BUF_VIDEO_RGB 0x02100000 #define BUF_VIDEO_YUY2 0x02110000 #define BUF_VIDEO_JPEG 0x02120000 @@ -142,13 +139,13 @@ struct buf_element_s { buf_element_t *next; unsigned char *mem; - unsigned char *content; /* start of raw content in pMem (without header etc) */ + unsigned char *content; /* start of raw content in pMem (without header etc) */ - int32_t size ; /* size of _content_ */ + int32_t size ; /* size of _content_ */ int32_t max_size; uint32_t type; - uint32_t PTS; /* presentation time stamp, used for a/v sync */ - uint32_t SCR; /* system clock reference, used for discont. detection */ + int64_t pts; /* presentation time stamp, used for a/v sync */ + int64_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 */ diff --git a/src/xine-engine/buffer_types.c b/src/xine-engine/buffer_types.c index 994cacd97..f9b66892f 100644 --- a/src/xine-engine/buffer_types.c +++ b/src/xine-engine/buffer_types.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: buffer_types.c,v 1.9 2002/01/15 17:30:51 miguelfreitas Exp $ + * $Id: buffer_types.c,v 1.10 2002/02/09 07:13:24 guenter Exp $ * * * contents: @@ -215,13 +215,6 @@ static video_db_t video_db[] = { }, { { - 0 - }, - BUF_VIDEO_FILL, - "" -}, -{ - { mmioFOURCC('r','a','w',' '), 0 }, diff --git a/src/xine-engine/metronom.c b/src/xine-engine/metronom.c index f2d4e2875..8dd7d81f3 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.52 2002/01/28 17:28:39 miguelfreitas Exp $ + * $Id: metronom.c,v 1.53 2002/02/09 07:13:24 guenter Exp $ */ #ifdef HAVE_CONFIG_H @@ -37,41 +37,20 @@ #include "xine_internal.h" #include "metronom.h" #include "xineutils.h" +#include "video_out.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_THRESHOLD 120000 -#define SCR_DISCONTINUITY 60000 -#define MAX_NUM_WRAP_DIFF 100 +#define MAX_NUM_WRAP_DIFF 10 #define MAX_SCR_PROVIDERS 10 #define PREBUFFER_PTS_OFFSET 30000 +#define VIDEO_DRIFT_TOLERANCE 45000 -#ifdef __GNUC__ -#define LOG_MSG_STDERR(xine, message, args...) { \ - xine_log((xine_t*)xine, XINE_LOG_METRONOM, message, ##args); \ - fprintf(stderr, message, ##args); \ - } -#define LOG_MSG(xine, message, args...) { \ - xine_log((xine_t*)xine, XINE_LOG_METRONOM, message, ##args); \ - printf(message, ##args); \ - } -#else -#define LOG_MSG_STDERR(xine, ...) { \ - xine_log((xine_t*)xine, XINE_LOG_METRONOM, __VA_ARGS__); \ - fprintf(stderr, __VA_ARGS__); \ - } -#define LOG_MSG(xine, ...) { \ - xine_log((xine_t*)xine, XINE_LOG_METRONOM, __VA_ARGS__); \ - printf(__VA_ARGS__); \ - } -#endif +#define METRONOM_REPORT -/* #define METRONOM_LOG -*/ + /* * **************************************** @@ -84,7 +63,7 @@ typedef struct unixscr_s { scr_plugin_t scr; struct timeval cur_time; - uint32_t cur_pts; + int64_t cur_pts; double speed_factor; pthread_mutex_t lock; @@ -99,7 +78,7 @@ static int unixscr_get_priority (scr_plugin_t *scr) { static void unixscr_set_pivot (unixscr_t *this) { struct timeval tv; - uint32_t pts; + int64_t pts; double pts_calc; gettimeofday(&tv, NULL); @@ -130,7 +109,7 @@ static int unixscr_set_speed (scr_plugin_t *scr, int speed) { return speed; } -static void unixscr_adjust (scr_plugin_t *scr, uint32_t vpts) { +static void unixscr_adjust (scr_plugin_t *scr, int64_t vpts) { unixscr_t *this = (unixscr_t*) scr; struct timeval tv; @@ -144,7 +123,7 @@ static void unixscr_adjust (scr_plugin_t *scr, uint32_t vpts) { pthread_mutex_unlock (&this->lock); } -static void unixscr_start (scr_plugin_t *scr, uint32_t start_vpts) { +static void unixscr_start (scr_plugin_t *scr, int64_t start_vpts) { unixscr_t *this = (unixscr_t*) scr; pthread_mutex_lock (&this->lock); @@ -155,11 +134,11 @@ static void unixscr_start (scr_plugin_t *scr, uint32_t start_vpts) { pthread_mutex_unlock (&this->lock); } -static uint32_t unixscr_get_current (scr_plugin_t *scr) { +static int64_t unixscr_get_current (scr_plugin_t *scr) { unixscr_t *this = (unixscr_t*) scr; struct timeval tv; - uint32_t pts; + int64_t pts; double pts_calc; pthread_mutex_lock (&this->lock); @@ -202,14 +181,17 @@ static scr_plugin_t* unixscr_init () { */ -static void metronom_start_clock (metronom_t *this, uint32_t pts) { +static void metronom_start_clock (metronom_t *this, int64_t pts) { scr_plugin_t** scr; + + printf ("metronom: start_clock (at %lld)\n", pts); + for (scr = this->scr_list; scr < this->scr_list+MAX_SCR_PROVIDERS; scr++) if (*scr) (*scr)->start(*scr, pts); } -static uint32_t metronom_get_current_time (metronom_t *this) { +static int64_t metronom_get_current_time (metronom_t *this) { return this->scr_master->get_current(this->scr_master); } @@ -228,7 +210,7 @@ static void metronom_resume_clock(metronom_t *this) { -static void metronom_adjust_clock(metronom_t *this, uint32_t desired_pts) { +static void metronom_adjust_clock(metronom_t *this, int64_t desired_pts) { this->scr_master->adjust(this->scr_master, desired_pts); } @@ -245,179 +227,8 @@ static int metronom_set_speed (metronom_t *this, int speed) { return true_speed; } -/* - * virtual pts calculation - */ - -static void metronom_video_stream_start (metronom_t *this) { - - pthread_mutex_lock (&this->lock); - - LOG_MSG(this->xine, _("metronom: video stream start...\n")); - - if (this->video_stream_running) { - LOG_MSG(this->xine, _("metronom: video stream start ignored\n")); - pthread_mutex_unlock (&this->lock); - return; - } - - /*this->pts_per_frame = 3000; */ - this->avg_frame_duration = this->pts_per_frame; - - this->video_vpts = PREBUFFER_PTS_OFFSET; - - this->last_video_pts = 0; - this->last_video_scr = 0; - this->num_video_vpts_guessed = 0; - - /* video_wrap_offset will be updated with the first pts */ - /* 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) { - LOG_MSG(this->xine, _("metronom: 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); - - metronom_start_clock (this, 0); -} - - -static void metronom_video_stream_end (metronom_t *this) { - - pthread_mutex_lock (&this->lock); - - LOG_MSG(this->xine, _("metronom: video stream end\n")); - - if (!this->video_stream_running) { - LOG_MSG(this->xine, _("metronom: video stream end ignored\n")); - pthread_mutex_unlock (&this->lock); - return; - } - - this->video_stream_running = 0; - - if (this->have_audio) { - /* while (this->audio_stream_running) { */ - if (this->audio_stream_running) { - LOG_MSG(this->xine, _("metronom: waiting for audio to end...\n")); - pthread_cond_wait (&this->audio_ended, &this->lock); - } - } - pthread_cond_signal (&this->video_ended); - - - pthread_mutex_unlock (&this->lock); -} - -static void metronom_audio_stream_start (metronom_t *this) { - - pthread_mutex_lock (&this->lock); - - LOG_MSG(this->xine, _("metronom: audio stream start...\n")); - - if (this->audio_stream_running) { - LOG_MSG(this->xine, _("metronom: audio stream start ignored\n")); - pthread_mutex_unlock (&this->lock); - return; - } - - this->audio_vpts = PREBUFFER_PTS_OFFSET; - - this->audio_pts_delta = 0; - - this->num_audio_samples_guessed = 1; - this->last_audio_pts = 0; - this->last_audio_scr = 0; - - /* audio_wrap_offset will be updated with the first pts */ - /* 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) { - LOG_MSG(this->xine, _("metronom: 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); - - LOG_MSG(this->xine, _("metronom: audio stream start...done\n")); - - metronom_start_clock (this, 0); -} - -static void metronom_audio_stream_end (metronom_t *this) { - - pthread_mutex_lock (&this->lock); - - LOG_MSG(this->xine, _("metronom: audio stream end\n")); - if (!this->audio_stream_running) { - LOG_MSG(this->xine, _("metronom: audio stream end ignored\n")); - pthread_mutex_unlock (&this->lock); - return; - } - - this->audio_stream_running = 0; - - /* while (this->video_stream_running) { */ - if (this->video_stream_running) { - LOG_MSG(this->xine, _("metronom: waiting for video to end...\n")); - pthread_cond_wait (&this->video_ended, &this->lock); - } - - pthread_cond_signal (&this->audio_ended); - pthread_mutex_unlock (&this->lock); -} - -static void metronom_set_video_rate (metronom_t *this, uint32_t pts_per_frame) { - pthread_mutex_lock (&this->lock); - - printf ("metronom: set_video_rate %d\n", pts_per_frame); - - this->pts_per_frame = pts_per_frame; - - this->avg_frame_duration = this->pts_per_frame; - - pthread_mutex_unlock (&this->lock); -} - -static uint32_t metronom_get_video_rate (metronom_t *this) { - int ret; - - pthread_mutex_lock (&this->lock); - ret = this->avg_frame_duration; - pthread_mutex_unlock (&this->lock); - - /* this is due bad streams, but returning 0 will - cause problems to video out timer setting. */ - if( ret < 100 ) - ret = 100; - return ret; -} - -static void metronom_set_audio_rate (metronom_t *this, uint32_t pts_per_smpls) { +static void metronom_set_audio_rate (metronom_t *this, int64_t pts_per_smpls) { pthread_mutex_lock (&this->lock); this->pts_per_smpls = pts_per_smpls; @@ -425,14 +236,14 @@ static void metronom_set_audio_rate (metronom_t *this, uint32_t pts_per_smpls) { pthread_mutex_unlock (&this->lock); #ifdef METRONOM_LOG - printf ("metronom: %d pts per %d samples\n", pts_per_smpls, AUDIO_SAMPLE_NUM); + printf ("metronom: %lld pts per %d samples\n", pts_per_smpls, AUDIO_SAMPLE_NUM); #endif } -static uint32_t metronom_got_spu_packet (metronom_t *this, uint32_t pts, - uint32_t duration, uint32_t scr ) { - uint32_t vpts; +static int64_t metronom_got_spu_packet (metronom_t *this, int64_t pts, + int64_t duration, int64_t scr ) { + int64_t vpts; pthread_mutex_lock (&this->lock); @@ -452,9 +263,7 @@ static uint32_t metronom_got_spu_packet (metronom_t *this, uint32_t pts, detected but this->video_wrap_offset not updated (would give wrong values too). */ - if ( this->video_stream_starting ) { - vpts = 0; - } else if ( this->video_discontinuity ) { + if ( this->video_discontinuity ) { /* we can safely use audio_wrap_offset if already updated */ if( !this->audio_discontinuity ) { vpts = pts + this->audio_wrap_offset; @@ -478,14 +287,14 @@ static void metronom_expect_video_discontinuity (metronom_t *this) { this->video_discontinuity_count++; pthread_cond_signal (&this->video_discontinuity_reached); - LOG_MSG(this->xine, _("metronom: video discontinuity #%d\n"), + printf ("metronom: video discontinuity #%d\n", this->video_discontinuity_count); if( this->have_audio ) { while ( this->audio_discontinuity_count < this->video_discontinuity_count ) { - LOG_MSG(this->xine, _("metronom: waiting for audio discontinuity #%d\n"), + printf ("metronom: waiting for audio discontinuity #%d\n", this->video_discontinuity_count); pthread_cond_wait (&this->audio_discontinuity_reached, &this->lock); @@ -493,56 +302,53 @@ static void metronom_expect_video_discontinuity (metronom_t *this) { if ( this->video_vpts < this->audio_vpts ) { this->video_vpts = this->audio_vpts; - LOG_MSG(this->xine, _("metronom: video vpts adjusted to %d\n"), this->video_vpts); + printf ("metronom: video vpts adjusted to %lld\n", this->video_vpts); } } - /* this->num_video_vpts_guessed = 0; */ - /* this->last_video_pts = this->video_vpts - this->video_wrap_offset; */ - /* - this->avg_frame_duration = this->pts_per_frame; - */ - this->frames_since_start = 0; - pthread_mutex_unlock (&this->lock); } -static uint32_t metronom_got_video_frame (metronom_t *this, uint32_t pts, uint32_t scr) { +static void metronom_got_video_frame (metronom_t *this, vo_frame_t *img) { - uint32_t vpts; - int pts_discontinuity = 0; + int64_t vpts; + int64_t pts = img->pts; + int64_t duration = img->duration; + int pts_discontinuity = 0; pthread_mutex_lock (&this->lock); - if( (this->audio_discontinuity || this->audio_stream_starting) && - (this->video_discontinuity || this->video_stream_starting) ) { - - /* this is needed to take care of still frame with no audio - were vpts are not updated. - we can only do it here because audio and video decoder threads - have just been synced */ - if ( this->video_vpts < metronom_get_current_time(this) ) { - this->video_vpts = metronom_get_current_time(this) + PREBUFFER_PTS_OFFSET; - this->audio_vpts = this->video_vpts; - LOG_MSG(this->xine, _("metronom: audio/video vpts too old, adjusted to %d\n"), - this->video_vpts); - } - } - /* check for pts discontinuities against the predicted pts value */ - if (pts && this->last_video_pts) { - vpts = this->last_video_pts + - (this->num_video_vpts_guessed+1) * this->avg_frame_duration; - if( ( pts > vpts && (pts - vpts) > WRAP_THRESHOLD ) || - ( pts < vpts && (vpts - pts) > WRAP_THRESHOLD ) ) { + if (pts) { + + int64_t diff, predicted_pts; + + predicted_pts = this->last_video_pts + duration; + + diff = pts - predicted_pts; + +#ifdef METRONOM_LOG + printf ("metronom: got video pts %lld, predicted %lld (= %lld + %lld) => diff %lld\n", + pts, predicted_pts, this->last_video_pts, duration, diff); +#endif + + if ( abs (diff) > WRAP_THRESHOLD ) { + pts_discontinuity = 1; +#ifdef METRONOM_LOG + printf ("metronom: this is a video discontinuity\n"); +#endif + /* - ignore discontinuities created by frame reordering around - the REAL discontinuity. :) - */ - if( !this->video_discontinuity && !this->video_stream_starting ) { + * ignore discontinuities created by frame reordering around + * the REAL discontinuity. :) + */ + if( !this->video_discontinuity ) { pts = 0; +#ifdef METRONOM_LOG + printf ("metronom: not expecting a video discontinuity => ignored\n"); +#endif } } } @@ -552,33 +358,33 @@ static uint32_t metronom_got_video_frame (metronom_t *this, uint32_t pts, uint32 * check if there was any pending SCR discontinuity (video_discontinuity * is set from the decoder loop) together with pts discont. */ - if ( (this->video_discontinuity && pts_discontinuity) || - this->video_stream_starting ) { + if (this->video_discontinuity && pts_discontinuity) { this->video_discontinuity = 0; - this->video_stream_starting = 0; this->wrap_diff_counter = 0; - this->video_wrap_offset = this->video_vpts + this->avg_frame_duration - pts; - /* + this->num_video_vpts_guessed * this->avg_frame_duration; */ + this->video_wrap_offset = this->video_vpts - pts; vpts = pts + this->video_wrap_offset; - LOG_MSG(this->xine, _("metronom: video pts discontinuity/start, pts is %d, wrap_offset is %d, vpts is %d\n"), + printf ("metronom: video pts discontinuity/start, pts is %lld, wrap_offset is %lld, vpts is %lld\n", pts, this->video_wrap_offset, vpts); } else { + int64_t diff; + /* * audio and video wrap are not allowed to differ for too long */ - if ( !this->audio_stream_starting && this->have_audio + + if ( this->have_audio && (this->video_wrap_offset != this->audio_wrap_offset) && !this->video_discontinuity && !this->audio_discontinuity ) { this->wrap_diff_counter++; if (this->wrap_diff_counter > MAX_NUM_WRAP_DIFF) { - LOG_MSG(this->xine, _("metronom: forcing video_wrap (%d) and audio wrap (%d)"), + printf ("metronom: forcing video_wrap (%lld) and audio wrap (%lld)", this->video_wrap_offset, this->audio_wrap_offset); if (this->video_wrap_offset > this->audio_wrap_offset) @@ -586,103 +392,64 @@ static uint32_t metronom_got_video_frame (metronom_t *this, uint32_t pts, uint32 else this->video_wrap_offset = this->audio_wrap_offset; - LOG_MSG(this->xine, _(" to %d\n"), this->video_wrap_offset); + printf (this->xine, " to %d\n", this->video_wrap_offset); this->wrap_diff_counter = 0; } } /* - * calc overall average frame duration (according to pts values) + * compare predicted (this->video_vpts) and given (pts+wrap_offset) + * pts values - hopefully they will be the same + * if not, for small diffs try to interpolate + * for big diffs: jump */ - if (this->frames_since_start && this->last_video_pts) { - int current_avg_delta; - - int weight_old = 9; - int weight_new = 1; - - /* - printf("foo: pts %d, last pts %d\n", pts, this->last_video_pts); - */ - - if (pts > this->last_video_pts) { - current_avg_delta = (pts - this->last_video_pts) / (this->num_video_vpts_guessed + 1); - - /* - printf("foo: current_avg_delta %d\n", current_avg_delta); - */ - - this->avg_frame_duration = - (((this->avg_frame_duration * weight_old) + (current_avg_delta * weight_new)) / - (weight_old + weight_new)); - } else { - current_avg_delta = (this->last_video_pts - pts) / (this->num_video_vpts_guessed + 1); - - /* - printf("foo: current_avg_delta - %d\n", current_avg_delta); - */ - this->avg_frame_duration = - (((this->avg_frame_duration * weight_old) - (current_avg_delta * weight_new)) / - (weight_old + weight_new)); - } - } - } + vpts = pts + this->video_wrap_offset; - this->last_video_pts = pts; - } + diff = this->video_vpts - vpts; - this->video_vpts += this->avg_frame_duration; +#ifdef METRONOM_LOG + printf ("metronom: video diff is %lld (predicted %lld, given %lld)\n", + diff, this->video_vpts, vpts); +#endif - /* - * smoothen possibly wrong pts as long as delta is small - */ + if (abs (diff) > VIDEO_DRIFT_TOLERANCE) { - if (pts) { - int drift; - int delta = this->video_vpts - this->video_wrap_offset - pts; + this->video_vpts = vpts; + this->video_wrap_offset = vpts - pts; #ifdef METRONOM_LOG - printf("metronom: delta (vpts <-> pts+wrap_offset): %d\n", delta); + printf ("metronom: video jump, wrap offset is now %lld\n", + this->video_wrap_offset); #endif + + } else if (diff) { - if (abs (delta) > 45000) { - - this->video_vpts = pts + this->video_wrap_offset; - - LOG_MSG(this->xine, _("metronom: delta too big, setting vpts to %d\n"), - this->video_vpts); + this->video_vpts -= diff / 8; /* FIXME: better heuristics ? */ + this->video_wrap_offset = vpts - pts; - - } else { - - if (this->num_video_vpts_guessed > 10) - this->num_video_vpts_guessed = 10; - - drift = delta / 20 * (this->num_video_vpts_guessed + 1); #ifdef METRONOM_LOG - printf("metronom: compensation drift: %d\n", drift); + printf ("metronom: video drift, wrap offset is now %lld\n", + this->video_wrap_offset); #endif - - this->video_vpts -= drift; + } } - this->num_video_vpts_guessed = 0; + this->last_video_pts = pts; } else - this->num_video_vpts_guessed++; + this->last_video_pts = this->video_vpts - this->video_wrap_offset; - this->frames_since_start++; + img->vpts = this->video_vpts + this->av_offset; #ifdef METRONOM_LOG - printf ("metronom: video vpts for %10d : %10d (avg_frame_duration %d)\n", - pts, this->video_vpts, this->avg_frame_duration); + printf ("metronom: video vpts for %10lld : %10lld\n", + pts, this->video_vpts); #endif - vpts = this->video_vpts + this->av_offset; - - pthread_mutex_unlock (&this->lock); + this->video_vpts += duration; - return vpts; + pthread_mutex_unlock (&this->lock); } static void metronom_expect_audio_discontinuity (metronom_t *this) { @@ -693,13 +460,13 @@ static void metronom_expect_audio_discontinuity (metronom_t *this) { this->audio_discontinuity_count++; pthread_cond_signal (&this->audio_discontinuity_reached); - LOG_MSG(this->xine, _("metronom: audio discontinuity #%d\n"), + printf ("metronom: audio discontinuity #%d\n", this->audio_discontinuity_count); while ( this->audio_discontinuity_count > this->video_discontinuity_count ) { - LOG_MSG(this->xine, _("metronom: waiting for video_discontinuity #%d\n"), + printf ("metronom: waiting for video_discontinuity #%d\n", this->audio_discontinuity_count); pthread_cond_wait (&this->video_discontinuity_reached, &this->lock); @@ -707,7 +474,7 @@ static void metronom_expect_audio_discontinuity (metronom_t *this) { if ( this->audio_vpts < this->video_vpts ) { this->audio_vpts = this->video_vpts; - LOG_MSG(this->xine, _("metronom: audio vpts adjusted to %d\n"), this->audio_vpts); + printf ("metronom: audio vpts adjusted to %lld\n", this->audio_vpts); } /* this->num_audio_samples_guessed = 1; */ @@ -717,20 +484,20 @@ static void metronom_expect_audio_discontinuity (metronom_t *this) { } -static uint32_t metronom_got_audio_samples (metronom_t *this, uint32_t pts, - uint32_t nsamples, uint32_t scr) { +static int64_t metronom_got_audio_samples (metronom_t *this, int64_t pts, + int nsamples, int64_t scr) { - uint32_t vpts; + int64_t vpts; #ifdef METRONOM_LOG - printf ("metronom: got %d samples, pts is %u, last_pts is %u, diff = %d\n", + printf ("metronom: got %d samples, pts is %lld, last_pts is %lld, diff = %lld\n", nsamples, pts, this->last_audio_pts, pts - this->last_audio_pts); #endif pthread_mutex_lock (&this->lock); - if( (this->audio_discontinuity || this->audio_stream_starting) && - (this->video_discontinuity || this->video_stream_starting) ) { +#if 0 + if (this->audio_discontinuity && this->video_discontinuity) { /* this is needed to take care of still frame with no audio were vpts are not updated. @@ -739,32 +506,31 @@ static uint32_t metronom_got_audio_samples (metronom_t *this, uint32_t pts, if ( this->audio_vpts < metronom_get_current_time(this) ) { this->audio_vpts = metronom_get_current_time(this) + PREBUFFER_PTS_OFFSET; this->video_vpts = this->audio_vpts; - LOG_MSG(this->xine, _("metronom: audio/video vpts too old, adjusted to %d\n"), + printf ("metronom: audio/video vpts too old, adjusted to %lld\n", this->audio_vpts); } } - - this->last_audio_scr = scr; +#endif if (pts) { /* * discontinuity ? */ - if ( this->audio_discontinuity || this->audio_stream_starting ) { + if ( this->audio_discontinuity ) { this->audio_discontinuity = 0; - this->audio_stream_starting = 0; this->wrap_diff_counter = 0; this->audio_wrap_offset = this->audio_vpts - 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 ; + */ vpts = pts + this->audio_wrap_offset; - LOG_MSG(this->xine, _("metronom: audio pts discontinuity/start, pts is %d, wrap_offset is %d, vpts is %d\n"), + printf ("metronom: audio pts discontinuity/start, pts is %lld, wrap_offset is %lld, vpts is %lld\n", pts, this->audio_wrap_offset, vpts); @@ -781,7 +547,7 @@ static uint32_t metronom_got_audio_samples (metronom_t *this, uint32_t pts, if (this->wrap_diff_counter > MAX_NUM_WRAP_DIFF) { - LOG_MSG(this->xine, _("metronom: forcing video_wrap (%d) and audio wrap (%d)"), + printf ("metronom: forcing video_wrap (%lld) and audio wrap (%lld)", this->video_wrap_offset, this->audio_wrap_offset); if (this->video_wrap_offset > this->audio_wrap_offset) @@ -789,7 +555,7 @@ static uint32_t metronom_got_audio_samples (metronom_t *this, uint32_t pts, else this->video_wrap_offset = this->audio_wrap_offset; - LOG_MSG(this->xine, _("to %d\n"), this->video_wrap_offset); + printf ("to %lld\n", this->video_wrap_offset); this->wrap_diff_counter = 0; } @@ -823,7 +589,7 @@ static uint32_t metronom_got_audio_samples (metronom_t *this, uint32_t pts, this->num_audio_samples_guessed += nsamples; #ifdef METRONOM_LOG - printf ("metronom: audio vpts for %10d : %10d\n", pts, vpts); + printf ("metronom: audio vpts for %10lld : %10lld\n", pts, vpts); #endif pthread_mutex_unlock (&this->lock); @@ -839,7 +605,7 @@ static void metronom_set_av_offset (metronom_t *this, int32_t pts) { pthread_mutex_unlock (&this->lock); - LOG_MSG(this->xine, _("metronom: av_offset=%d pts\n"), pts); + printf ("metronom: av_offset=%d pts\n", pts); } static int32_t metronom_get_av_offset (metronom_t *this) { @@ -859,7 +625,7 @@ static scr_plugin_t* get_master_scr(metronom_t *this) { } } if (select < 0) { - LOG_MSG(this->xine, _("metronom: panic - no scr provider found!\n")); + printf ("metronom: panic - no scr provider found!\n"); return NULL; } return this->scr_list[select]; @@ -896,8 +662,9 @@ static void metronom_unregister_scr (metronom_t *this, scr_plugin_t *scr) { } static int metronom_sync_loop (metronom_t *this) { + scr_plugin_t** scr; - uint32_t pts; + int64_t pts; while (((xine_t*)this->xine)->status != XINE_QUIT) { pts = this->scr_master->get_current(this->scr_master); @@ -917,12 +684,6 @@ metronom_t * metronom_init (int have_audio, void *xine) { int err; this->xine = xine; - this->audio_stream_start = metronom_audio_stream_start; - this->audio_stream_end = metronom_audio_stream_end ; - this->video_stream_start = metronom_video_stream_start; - this->video_stream_end = metronom_video_stream_end ; - this->set_video_rate = metronom_set_video_rate; - this->get_video_rate = metronom_get_video_rate; this->set_audio_rate = metronom_set_audio_rate; this->got_video_frame = metronom_got_video_frame; this->got_audio_samples = metronom_got_audio_samples; @@ -945,20 +706,50 @@ metronom_t * metronom_init (int have_audio, void *xine) { if ((err = pthread_create(&this->sync_thread, NULL, (void*(*)(void*)) metronom_sync_loop, this)) != 0) - LOG_MSG(this->xine, _("metronom: cannot create sync thread (%s)\n"), + 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; - this->pts_per_frame = 3600; + + + /* initialize video stuff */ + + this->have_audio = have_audio; + this->video_vpts = PREBUFFER_PTS_OFFSET; + + this->last_video_pts = 0; + + this->video_wrap_offset = PREBUFFER_PTS_OFFSET; + this->wrap_diff_counter = 0; + + this->video_discontinuity = 0; + this->video_discontinuity_count = 0; + + /* initialize audio stuff */ + + this->audio_vpts = PREBUFFER_PTS_OFFSET; + + this->audio_pts_delta = 0; + + this->num_audio_samples_guessed = 1; + this->last_audio_pts = 0; + + this->audio_wrap_offset = PREBUFFER_PTS_OFFSET; + this->wrap_diff_counter = 0; + + this->audio_discontinuity = 0; + this->audio_discontinuity_count = 0; return this; } + + + + + + + diff --git a/src/xine-engine/metronom.h b/src/xine-engine/metronom.h index 18dd2ca8e..1b6a841cc 100644 --- a/src/xine-engine/metronom.h +++ b/src/xine-engine/metronom.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000-2001 the xine project + * Copyright (C) 2000-2002 the xine project * * This file is part of xine, a unix video player. * @@ -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.16 2001/12/27 14:30:30 f1rmb Exp $ + * $Id: metronom.h,v 1.17 2002/02/09 07:13:24 guenter Exp $ * * metronom: general pts => virtual calculation/assoc * @@ -50,6 +50,7 @@ extern "C" { #include <inttypes.h> #include <sys/time.h> #include <pthread.h> +#include "video_out.h" typedef struct metronom_s metronom_t ; typedef struct scr_plugin_s scr_plugin_t; @@ -63,58 +64,26 @@ struct metronom_s { void *xine; /* - * this is called to tell metronom to prepare for a new video stream - * (video and audio decoder threads may be blocked at these functions - * to synchronize starting and stopping) - */ - - 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 - * (video and audio decoder threads may be blocked at these functions - * to synchronize starting and stopping) - */ - - 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 - * - * parameter pts_per_frame : frame display duration in 1/90000 sec - */ - void (*set_video_rate) (metronom_t *this, uint32_t pts_per_frame); - - /* - * return current video rate (including delta corrections) - */ - - uint32_t (*get_video_rate) (metronom_t *this); - - /* * called by audio output driver to inform metronom about current audio - * bitrate + * samplerate * * parameter pts_per_smpls : 1/90000 sec per 65536 samples */ - void (*set_audio_rate) (metronom_t *this, uint32_t pts_per_smpls); + void (*set_audio_rate) (metronom_t *this, int64_t pts_per_smpls); /* * 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 + * parameter frame containing pts, scr, ... information * - * return value: virtual pts for frame (interpolated if pts == 0) + * will set vpts field in frame * * this function will also update video_wrap_offset if a discontinuity * is detected (read the comentaries below about discontinuities). * */ - uint32_t (*got_video_frame) (metronom_t *this, uint32_t pts, uint32_t scr); + void (*got_video_frame) (metronom_t *this, vo_frame_t *frame); /* * called by audio output driver whenever audio samples are delivered to it @@ -130,7 +99,8 @@ struct metronom_s { * */ - uint32_t (*got_audio_samples) (metronom_t *this, uint32_t pts, uint32_t nsamples, uint32_t scr); + int64_t (*got_audio_samples) (metronom_t *this, int64_t pts, + int nsamples, int64_t scr); /* * called by SPU decoder whenever a packet is delivered to it @@ -143,17 +113,17 @@ struct metronom_s { * due to the lack of regularity on spu packets) */ - uint32_t (*got_spu_packet) (metronom_t *this, uint32_t pts, uint32_t duration, - uint32_t scr); + int64_t (*got_spu_packet) (metronom_t *this, int64_t pts, int64_t duration, + int64_t scr); /* - * Tell metronom about discontinuities. + * tell metronom about discontinuities. * - * These functions are called due to a discontinuity detected at + * these functions are called due to a discontinuity detected at * demux stage from SCR values. As SCR are not guarateed to happen with * any regularity, we can not correct the xxx_wrap_offset right now. * - * We will instead prepare both audio and video to correct the + * we will instead prepare both audio and video to correct the * discontinuity at the first new PTS value (got_video_frame or * got_audio_samples). As we can predict with reasonably accuracy what * the old PTS would have being the calculated wrap_offset should be @@ -185,7 +155,7 @@ struct metronom_s { * start metronom clock (no clock reset) * at given pts */ - void (*start_clock) (metronom_t *this, uint32_t pts); + void (*start_clock) (metronom_t *this, int64_t pts); /* @@ -203,13 +173,13 @@ struct metronom_s { /* * get current clock value in vpts */ - uint32_t (*get_current_time) (metronom_t *this); + int64_t (*get_current_time) (metronom_t *this); /* * adjust master clock to external timer (e.g. audio hardware) */ - void (*adjust_clock) (metronom_t *this, uint32_t desired_pts); + void (*adjust_clock) (metronom_t *this, int64_t desired_pts); /* @@ -229,28 +199,24 @@ struct metronom_s { * metronom internal stuff */ - uint32_t pts_per_frame; - uint32_t pts_per_smpls; + int64_t pts_per_smpls; - int32_t audio_pts_delta; + int64_t audio_pts_delta; - uint32_t video_vpts; - uint32_t spu_vpts; - uint32_t audio_vpts; + int64_t video_vpts; + int64_t spu_vpts; + int64_t audio_vpts; - int32_t video_wrap_offset; - int32_t audio_wrap_offset; + int64_t video_wrap_offset; + int64_t audio_wrap_offset; int wrap_diff_counter; - uint32_t last_video_pts; - uint32_t last_video_scr; - int num_video_vpts_guessed; + int64_t last_video_pts; - uint32_t last_audio_pts; - uint32_t last_audio_scr; + int64_t last_audio_pts; int num_audio_samples_guessed; - int32_t av_offset; + int64_t av_offset; scr_plugin_t* scr_master; scr_plugin_t** scr_list; @@ -259,29 +225,19 @@ struct metronom_s { pthread_mutex_t lock; int have_audio; - int video_stream_starting; - int video_stream_running; - 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; - pthread_cond_t audio_ended; - int frames_since_start; - int avg_frame_duration; }; metronom_t *metronom_init (int have_audio, void *xine); /* - * SCR plugins + * SCR (system clock reference) plugins */ struct scr_plugin_s @@ -299,11 +255,11 @@ struct scr_plugin_s int (*set_speed) (scr_plugin_t *this, int speed); - void (*adjust) (scr_plugin_t *this, uint32_t vpts); + void (*adjust) (scr_plugin_t *this, int64_t vpts); - void (*start) (scr_plugin_t *this, uint32_t start_vpts); + void (*start) (scr_plugin_t *this, int64_t start_vpts); - uint32_t (*get_current) (scr_plugin_t *this); + int64_t (*get_current) (scr_plugin_t *this); metronom_t *metronom; }; diff --git a/src/xine-engine/video_decoder.c b/src/xine-engine/video_decoder.c index 6c0f1db43..d14467557 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.71 2002/01/25 00:35:46 f1rmb Exp $ + * $Id: video_decoder.c,v 1.72 2002/02/09 07:13:24 guenter Exp $ * */ @@ -105,8 +105,8 @@ void *video_decoder_loop (void *this_gen) { this->spu_finished = 0; pthread_mutex_unlock (&this->finished_lock); - - this->metronom->video_stream_start (this->metronom); + + this->metronom->expect_video_discontinuity (this->metronom); break; @@ -144,8 +144,6 @@ 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; @@ -184,15 +182,8 @@ void *video_decoder_loop (void *this_gen) { 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"); - if (this->cur_video_decoder_plugin) - this->cur_video_decoder_plugin->flush (this->cur_video_decoder_plugin); - this->video_in_discontinuity = 1; this->metronom->expect_video_discontinuity (this->metronom); @@ -200,14 +191,6 @@ void *video_decoder_loop (void *this_gen) { this->video_in_discontinuity = 0; break; - case BUF_VIDEO_FILL: - break; - - case BUF_CONTROL_FLUSH: - if (this->cur_video_decoder_plugin) - this->cur_video_decoder_plugin->flush (this->cur_video_decoder_plugin); - break; - case BUF_CONTROL_AUDIO_CHANNEL: { xine_ui_event_t ui_event; diff --git a/src/xine-engine/video_out.c b/src/xine-engine/video_out.c index 8f43d71ce..10a327045 100644 --- a/src/xine-engine/video_out.c +++ b/src/xine-engine/video_out.c @@ -17,8 +17,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: video_out.c,v 1.70 2002/02/02 13:39:30 miguelfreitas Exp $ + * $Id: video_out.c,v 1.71 2002/02/09 07:13:24 guenter Exp $ * + * frame allocation / queuing / scheduling / output functions */ #ifdef HAVE_CONFIG_H @@ -34,6 +35,7 @@ #include <zlib.h> #include "video_out.h" +#include "metronom.h" #include "xine_internal.h" #include "xineutils.h" @@ -57,12 +59,48 @@ } #endif -/* + #define VIDEO_OUT_LOG -*/ #define NUM_FRAME_BUFFERS 15 +typedef struct { + + vo_instance_t vo; /* public part */ + + vo_driver_t *driver; + metronom_t *metronom; + xine_t *xine; + + img_buf_fifo_t *free_img_buf_queue; + img_buf_fifo_t *display_img_buf_queue; + + vo_frame_t *last_frame; + vo_frame_t *img_backup; + int backup_is_logo; + + int video_loop_running; + int video_opened; + pthread_t video_thread; + + int num_frames_delivered; + int num_frames_skipped; + int num_frames_discarded; + + /* pts value when decoder delivered last video frame */ + int64_t last_delivery_pts; + + int logo_w, logo_h; + uint8_t *logo_yuy2; + + video_overlay_instance_t *overlay_source; + int overlay_enabled; +} vos_t; + +/* + * frame queue (fifo) util functions + */ + struct img_buf_fifo_s { vo_frame_t *first; vo_frame_t *last; @@ -144,439 +182,521 @@ static vo_frame_t *vo_remove_from_img_buf_queue (img_buf_fifo_t *queue) { return img; } -static void vo_set_timer (uint32_t video_step) { - struct itimerval tval; - - tval.it_interval.tv_sec = 0; - tval.it_interval.tv_usec = video_step*100000/90000; - tval.it_value.tv_sec = 0; - tval.it_value.tv_usec = video_step*100000/90000; - - if (setitimer(ITIMER_REAL, &tval, NULL)) { - printf ("vo_set_timer: setitimer failed :"); - } -} +/* + * function called by video output driver + */ -void video_timer_handler (int hubba) { -#if !HAVE_SIGACTION - signal (SIGALRM, video_timer_handler); -#endif -} +static void vo_frame_displayed (vo_frame_t *img) { -/* send a buf to force video_decoder->flush */ -static void video_out_send_decoder_flush( fifo_buffer_t *video_fifo ) { - buf_element_t *buf; + pthread_mutex_lock (&img->mutex); - if( !video_fifo ) - return; - - buf = video_fifo->buffer_pool_alloc (video_fifo); - - buf->type = BUF_CONTROL_FLUSH ; - buf->PTS = 0; - buf->SCR = 0; - buf->input_pos = 0; - buf->input_time = 0; + img->driver_locked = 0; - video_fifo->put (video_fifo, buf); + if (!img->decoder_locked) { + vos_t *this = (vos_t *) img->instance; + vo_append_to_img_buf_queue (this->free_img_buf_queue, img); + } + pthread_mutex_unlock (&img->mutex); } -static vo_frame_t *vo_get_frame (vo_instance_t *this, +/* + * + * functions called by video decoder: + * + * get_frame => alloc frame for rendering + * + * frame_draw=> queue finished frame for display + * + * frame_free=> frame no longer used as reference frame by decoder + * + */ + +static vo_frame_t *vo_get_frame (vo_instance_t *this_gen, uint32_t width, uint32_t height, - int ratio, int format, uint32_t duration, + int ratio, int format, int flags) { vo_frame_t *img; + vos_t *this = (vos_t *) this_gen; - /* - printf ("video_out : get_frame %d x %d from queue %d\n", - width, height, this->free_img_buf_queue); - fflush(stdout); - */ - - if (this->pts_per_frame != duration) { - this->pts_per_frame = duration; - this->pts_per_half_frame = duration / 2; - this->metronom->set_video_rate (this->metronom, duration); - } +#ifdef VIDEO_OUT_LOG + printf ("video_out: get_frame (%d x %d)\n", width, height); +#endif img = vo_remove_from_img_buf_queue (this->free_img_buf_queue); +#ifdef VIDEO_OUT_LOG + printf ("video_out: got a frame -> pthread_mutex_lock (&img->mutex)\n"); +#endif + pthread_mutex_lock (&img->mutex); img->display_locked = 0; img->decoder_locked = 1; img->driver_locked = 0; - img->width = width; - img->height = height; - img->ratio = ratio; - img->format = format; - img->duration = duration; - img->drawn = 0; + img->width = width; + img->height = height; + img->ratio = ratio; + img->format = format; /* let driver ensure this image has the right format */ - this->driver->update_frame_format (this->driver, img, width, height, ratio, format, flags); + this->driver->update_frame_format (this->driver, img, width, height, + ratio, format, flags); pthread_mutex_unlock (&img->mutex); +#ifdef VIDEO_OUT_LOG + printf ("video_out: get_frame (%d x %d) done\n", width, height); +#endif + return img; } -static void *video_out_loop (void *this_gen) { +static int vo_frame_draw (vo_frame_t *img) { - uint32_t cur_pts; - int diff, absdiff, pts=0; - vo_frame_t *img, *img_backup; - int backup_is_logo = 0; - uint32_t video_step, video_step_new; - vo_instance_t *this = (vo_instance_t *) this_gen; - static int prof_video_out = -1; - static int prof_spu_blend = -1; - sigset_t vo_mask; - - int flush_sent = 0; + vos_t *this = (vos_t *) img->instance; + int64_t diff; + int64_t cur_vpts; + int64_t pic_vpts ; + int frames_to_skip; - /* printf ("%d video_out start\n", getpid()); */ + this->metronom->got_video_frame (this->metronom, img); - if (prof_video_out == -1) - prof_video_out = xine_profiler_allocate_slot ("video output"); - if (prof_spu_blend == -1) - prof_spu_blend = xine_profiler_allocate_slot ("spu blend"); + pic_vpts = img->vpts; - img_backup = NULL; - this->last_draw_vpts = 0; - - /* - * set up timer signal - */ - - sigemptyset(&vo_mask); - sigaddset(&vo_mask, SIGALRM); - if (sigprocmask (SIG_UNBLOCK, &vo_mask, NULL)) { - LOG_MSG(this->xine, _("video_out: sigprocmask failed.\n")); - } -#if HAVE_SIGACTION - { - struct sigaction sig_act; - memset (&sig_act, 0, sizeof(sig_act)); - sig_act.sa_handler = video_timer_handler; - sigaction (SIGALRM, &sig_act, NULL); - } -#else - signal (SIGALRM, video_timer_handler); -#endif + cur_vpts = this->metronom->get_current_time(this->metronom); + this->last_delivery_pts = cur_vpts; - video_step = this->metronom->get_video_rate (this->metronom); - vo_set_timer (video_step); +#ifdef VIDEO_OUT_LOG + printf ("video_out: got image at master vpts %lld. vpts for picture is %lld (pts was %lld)\n", + cur_vpts, pic_vpts, pic_vpts); +#endif - /* - * here it is - the big video output loop - */ + this->num_frames_delivered++; - while ( this->video_loop_running ) { + diff = pic_vpts - cur_vpts; + frames_to_skip = ((-1 * diff) / img->duration + 3) * 2; - /* - * wait until it's time to display a frame - */ - - pause (); +#ifdef VIDEO_OUT_LOG + printf ("video_out: delivery diff : %lld, current vpts is %lld\n", + diff, cur_vpts); +#endif - video_step_new = this->metronom->get_video_rate (this->metronom); - if (video_step_new != video_step) { - video_step = video_step_new; - - vo_set_timer (video_step); - } - - /* - * now, look at the frame queue and decide which frame to display - * or generate still frames if no frames are available - */ + if (img->display_locked) { + printf ("video_out: ALERT! frame is already locked for displaying\n"); + return frames_to_skip; + } - xine_profiler_start_count (prof_video_out); + if (cur_vpts>0) { - cur_pts = this->metronom->get_current_time (this->metronom); + if (diff<(-1 * img->duration) && img->drawn != 2 ) { + this->num_frames_discarded++; #ifdef VIDEO_OUT_LOG - printf ("video_out : video loop iteration at audio pts %d\n", cur_pts); + printf ("video_out: frame rejected, %d frames to skip\n", frames_to_skip); #endif - - img = this->display_img_buf_queue->first; - /* update timer for inactivity flush */ - if( img ) { - this->last_draw_vpts = cur_pts; - } else { - /* start timer when decoder receives the first packet */ - if( !this->last_draw_vpts && this->decoder_started_flag ) - this->last_draw_vpts = cur_pts; - - if( this->last_draw_vpts && (cur_pts - this->last_draw_vpts) > (8 * this->pts_per_frame) ) { -#ifdef VIDEO_OUT_LOG - printf("video_out : sending decoder flush due to inactivity\n"); -#endif - video_out_send_decoder_flush( this->xine->video_fifo ); - this->last_draw_vpts = cur_pts; - flush_sent = 1; - } + pthread_mutex_lock (&img->mutex); + img->display_locked = 0; + pthread_mutex_unlock (&img->mutex); + + vo_frame_displayed (img); + + this->last_frame = img; + + return frames_to_skip; + } - - + } /* else: we are probably in precaching mode */ + + if (!img->bad_frame) { /* - * throw away expired frames + * put frame into FIFO-Buffer */ - diff = 1000000; +#ifdef VIDEO_OUT_LOG + printf ("video_out: frame is ok => appending to display buffer\n"); +#endif + + this->last_frame = img; + + pthread_mutex_lock (&img->mutex); + img->display_locked = 1; + pthread_mutex_unlock (&img->mutex); + + vo_append_to_img_buf_queue (this->display_img_buf_queue, img); + + } else { + this->num_frames_skipped++; + + pthread_mutex_lock (&img->mutex); + img->display_locked = 0; + pthread_mutex_unlock (&img->mutex); + + vo_frame_displayed (img); + } + + /* + * performance measurement + */ + + if (this->num_frames_delivered>199) { + LOG_MSG_STDERR(this->xine, + _("%d frames delivered, %d frames skipped, %d frames discarded\n"), + this->num_frames_delivered, + this->num_frames_skipped, this->num_frames_discarded); + + this->num_frames_delivered = 0; + this->num_frames_discarded = 0; + this->num_frames_skipped = 0; + } + + return frames_to_skip; +} + +static void vo_frame_free (vo_frame_t *img) { + + pthread_mutex_lock (&img->mutex); + img->decoder_locked = 0; + + if (!img->display_locked && !img->driver_locked ) { + vos_t *this = (vos_t *) img->instance; + vo_append_to_img_buf_queue (this->free_img_buf_queue, img); + } + + pthread_mutex_unlock (&img->mutex); +} + + + +/* + * + * video out loop related functions + * + */ + +static void expire_frames (vos_t *this, int64_t cur_vpts) { + + int64_t pts; + int64_t diff; + vo_frame_t *img; + + img = this->display_img_buf_queue->first; + + /* + * throw away expired frames + */ + + diff = 1000000; /* always enter the while-loop */ - while (img && (diff >this->pts_per_half_frame)) { - pts = img->PTS; - diff = cur_pts - pts; - absdiff = abs(diff); + while (img && (diff > img->duration)) { + pts = img->vpts; + diff = cur_vpts - pts; - if (diff >this->pts_per_half_frame) { - LOG_MSG(this->xine, _("video_out : throwing away image with pts %d because " - "it's too old (diff : %d > %d).\n"), - pts, diff, this->pts_per_half_frame); + if (diff > img->duration) { + LOG_MSG(this->xine, + _("video_out: throwing away image with pts %lld because " + "it's too old (diff : %lld).\n"), pts, diff); - this->num_frames_discarded++; + this->num_frames_discarded++; - img = vo_remove_from_img_buf_queue (this->display_img_buf_queue); + img = vo_remove_from_img_buf_queue (this->display_img_buf_queue); - /* - * last frame? back it up for - * still frame creation - */ + /* + * last frame? back it up for + * still frame creation + */ - if (!this->display_img_buf_queue->first) { + if (!this->display_img_buf_queue->first) { - if (img_backup) { - pthread_mutex_lock (&img_backup->mutex); + if (this->img_backup) { + pthread_mutex_lock (&this->img_backup->mutex); #ifdef VIDEO_OUT_LOG - printf("video_out : overwriting frame backup\n"); + printf("video_out: overwriting frame backup\n"); #endif - img_backup->display_locked = 0; - if (!img->decoder_locked) - vo_append_to_img_buf_queue (this->free_img_buf_queue, img_backup); - - pthread_mutex_unlock (&img_backup->mutex); - } - printf("video_out : possible still frame (old)\n"); - flush_sent = 0; - - /* we must not clear display_locked from img_backup. - without it decoder may try to free our backup. */ - img_backup = img; - backup_is_logo = 0; - } else { - pthread_mutex_lock (&img->mutex); - - img->display_locked = 0; + this->img_backup->display_locked = 0; if (!img->decoder_locked) - vo_append_to_img_buf_queue (this->free_img_buf_queue, img); - - pthread_mutex_unlock (&img->mutex); + vo_append_to_img_buf_queue (this->free_img_buf_queue, + this->img_backup); + + pthread_mutex_unlock (&this->img_backup->mutex); } - - img = this->display_img_buf_queue->first; + printf("video_out: possible still frame (old)\n"); + + /* we must not clear display_locked from img_backup. + without it decoder may try to free our backup. */ + this->img_backup = img; + this->backup_is_logo = 0; + } else { + pthread_mutex_lock (&img->mutex); + + img->display_locked = 0; + if (!img->decoder_locked) + vo_append_to_img_buf_queue (this->free_img_buf_queue, img); + + pthread_mutex_unlock (&img->mutex); } - } + + img = this->display_img_buf_queue->first; + } + } - /* - * still frame detection: - */ +} + +static vo_frame_t *get_next_frame (vos_t *this, int64_t cur_vpts) { + + vo_frame_t *img; + + img = this->display_img_buf_queue->first; + + /* + * still frame detection: + */ - /* no frame? => still frame detection */ + /* no frame? => still frame detection */ - if (!img) { + if (!img) { #ifdef VIDEO_OUT_LOG - printf ("video_out : no frame\n"); + printf ("video_out: no frame\n"); #endif - /* - * display logo ? - */ - if (!this->video_opened && (!img_backup || !backup_is_logo)) { + /* + * display logo ? + */ + if (!this->video_opened && (!this->img_backup || !this->backup_is_logo)) { - if (img_backup) { - pthread_mutex_lock (&img_backup->mutex); + if (this->img_backup) { + pthread_mutex_lock (&this->img_backup->mutex); #ifdef VIDEO_OUT_LOG - printf("video_out : overwriting frame backup\n"); + printf("video_out: overwriting frame backup\n"); #endif - img_backup->display_locked = 0; - if (!img_backup->decoder_locked) - vo_append_to_img_buf_queue (this->free_img_buf_queue, img_backup); + this->img_backup->display_locked = 0; + if (!this->img_backup->decoder_locked) + vo_append_to_img_buf_queue (this->free_img_buf_queue, + this->img_backup); - pthread_mutex_unlock (&img_backup->mutex); - } + pthread_mutex_unlock (&this->img_backup->mutex); + } - printf("video_out : copying logo image\n"); + printf("video_out: copying logo image\n"); - img_backup = vo_get_frame (this, this->logo_w, this->logo_h, - 42, IMGFMT_YUY2, 6000, VO_BOTH_FIELDS); - - img_backup->decoder_locked = 0; - img_backup->display_locked = 1; - img_backup->driver_locked = 0; - - xine_fast_memcpy(img_backup->base[0], this->logo_yuy2, - this->logo_w*this->logo_h*2); - - /* this shouldn't be needed, duplicate_frame will call - img->copy for us. [mf] - if (img_backup->copy) { - int height = this->logo_h; - int stride = this->logo_w; - uint8_t* src[3]; - - src[0] = img_backup->base[0]; - - while ((height -= 16) >= 0) { - img_backup->copy(img_backup, src); - src[0] += 32 * stride; - } - } - */ - - backup_is_logo = 1; - } + this->img_backup = vo_get_frame (&this->vo, this->logo_w, this->logo_h, + 42, IMGFMT_YUY2, VO_BOTH_FIELDS); + this->img_backup->decoder_locked = 0; + this->img_backup->display_locked = 1; + this->img_backup->driver_locked = 0; + this->img_backup->duration = 10000; - if (img_backup) { + xine_fast_memcpy(this->img_backup->base[0], this->logo_yuy2, + this->logo_w*this->logo_h*2); - /* - * wait until it's time to display this still frame - */ - pts = this->metronom->get_current_time (this->metronom); - do { - xine_usec_sleep ( 10000 ); - cur_pts = this->metronom->get_current_time (this->metronom); - /* using abs will avoid problems if metronom gets updated */ - diff = abs(cur_pts - pts); - - } while (diff < 2 * this->pts_per_frame) ; + this->backup_is_logo = 1; + } - /* if some frame arrived dont generate still */ - if( this->display_img_buf_queue->first ) { - xine_profiler_stop_count (prof_video_out); - continue; - } + if (this->img_backup) { #ifdef VIDEO_OUT_LOG - printf("video_out : generating still frame (cur_pts = %d) \n", cur_pts); + printf("video_out: generating still frame (cur_vpts = %lld) \n", + cur_vpts); #endif - /* keep playing still frames */ - img = this->duplicate_frame( this, img_backup ); - img->display_locked = 1; + /* keep playing still frames */ + img = this->vo.duplicate_frame (&this->vo, this->img_backup ); + img->display_locked = 1; - img->PTS = cur_pts; - diff = 0; + do { + this->metronom->got_video_frame(this->metronom, img); + } while (img->vpts < cur_vpts); - } else { + return img; + + } else { #ifdef VIDEO_OUT_LOG - printf ("video_out : no frame, but no backup frame\n"); + printf ("video_out: no frame, but no backup frame\n"); #endif - xine_profiler_stop_count (prof_video_out); - continue; - } - } else { + return NULL; + } + } else { - /* - * time to display frame >img< ? - */ + int64_t diff; + + diff = cur_vpts - img->vpts; + + /* + * time to display frame "img" ? + */ #ifdef VIDEO_OUT_LOG - printf ("video_out : diff %d\n", diff); + printf ("video_out: diff %lld\n", diff); #endif - if (diff<0) { - xine_profiler_stop_count (prof_video_out); - continue; - } + if (diff < 0) { + return 0; + } - if (img_backup) { - pthread_mutex_lock (&img_backup->mutex); - printf("video_out : freeing frame backup\n"); + if (this->img_backup) { + pthread_mutex_lock (&this->img_backup->mutex); + printf("video_out: freeing frame backup\n"); - img_backup->display_locked = 0; - if( !img_backup->decoder_locked ) - vo_append_to_img_buf_queue (this->free_img_buf_queue, img_backup); - pthread_mutex_unlock (&img_backup->mutex); - img_backup = NULL; - } + this->img_backup->display_locked = 0; + if( !this->img_backup->decoder_locked ) + vo_append_to_img_buf_queue (this->free_img_buf_queue, + this->img_backup); + pthread_mutex_unlock (&this->img_backup->mutex); + this->img_backup = NULL; + } - /* - * last frame? make backup for possible still image - */ - if (img && !img->next && - (this->xine->video_fifo->size(this->xine->video_fifo) < 10 || - flush_sent || this->xine->video_in_discontinuity) ) { + /* + * last frame? make backup for possible still image + */ + if (img && !img->next && + (this->xine->video_fifo->size(this->xine->video_fifo) < 10 + || this->xine->video_in_discontinuity) ) { - printf("video_out : possible still frame (fifosize = %d, flushsent=%d)\n", - this->xine->video_fifo->size(this->xine->video_fifo), flush_sent); + printf ("video_out: possible still frame (fifosize = %d)\n", + this->xine->video_fifo->size(this->xine->video_fifo)); - img_backup = this->duplicate_frame(this, img); - backup_is_logo = 0; - } + this->img_backup = this->vo.duplicate_frame (&this->vo, img); + this->backup_is_logo = 0; + } - flush_sent = 0; - - /* - * remove frame from display queue and show it - */ + /* + * remove frame from display queue and show it + */ - img = vo_remove_from_img_buf_queue (this->display_img_buf_queue); + img = vo_remove_from_img_buf_queue (this->display_img_buf_queue); - if (!img) { - xine_profiler_stop_count (prof_video_out); - continue; - } - } + return img; + } +} + +static void overlay_and_display_frame (vos_t *this, + vo_frame_t *img) { + +#ifdef VIDEO_OUT_LOG + printf ("video_out: displaying image with vpts = %lld\n", + img->vpts); +#endif + + pthread_mutex_lock (&img->mutex); + img->driver_locked = 1; + +#ifdef VIDEO_OUT_LOG + if (!img->display_locked) + printf ("video_out: ALERT! frame was not locked for display queue\n"); +#endif + + img->display_locked = 0; + pthread_mutex_unlock (&img->mutex); + +#ifdef VIDEO_OUT_LOG + printf ("video_out: passing to video driver image with pts = %lld\n", + img->vpts); +#endif + + if (this->overlay_source) { + /* This is the only way for the overlay manager to get pts values + * for flushing its buffers. So don't remove it! */ + + this->overlay_source->multiple_overlay_blend (this->overlay_source, + img->vpts, + this->driver, img, + this->video_loop_running && this->overlay_enabled); + } + + this->driver->display_frame (this->driver, img); +} + +static void *video_out_loop (void *this_gen) { + + int64_t vpts, diff; + vo_frame_t *img; + vos_t *this = (vos_t *) this_gen; + int64_t frame_duration, next_frame_pts; + int64_t usec_to_sleep; + + /* + * here it is - the heart of xine (or rather: one of the hearts + * of xine) : the video output loop + */ + + frame_duration = 1500; /* default */ + next_frame_pts = 0; + +#ifdef VIDEO_OUT_LOG + printf ("video_out: loop starting...\n"); +#endif + + while ( this->video_loop_running ) { /* - * from this point on, img must be a valid frame for - * overlay and output + * get current time and find frame to display */ + vpts = this->metronom->get_current_time (this->metronom); #ifdef VIDEO_OUT_LOG - printf ("video_out : displaying image with pts = %d (diff=%d)\n", pts, diff); + printf ("video_out: loop iteration at %lld\n", vpts); #endif + expire_frames (this, vpts); + img = get_next_frame (this, vpts); - pthread_mutex_lock (&img->mutex); - img->driver_locked = 1; + /* + * if we have found a frame, display it + */ + + if (img) + overlay_and_display_frame (this, img); + + /* + * if we haven't heared from the decoder for some time + * flush it + */ + + diff = vpts - this->last_delivery_pts; + if (diff > 30000) { + if (this->xine->cur_video_decoder_plugin) { + this->xine->cur_video_decoder_plugin->flush(this->xine->cur_video_decoder_plugin); #ifdef VIDEO_OUT_LOG - if (!img->display_locked) - printf ("video_out : ALERT! frame was not locked for display queue\n"); + printf ("video_out: flushing current video decoder plugin\n"); #endif - img->display_locked = 0; - pthread_mutex_unlock (&img->mutex); + } + } + + /* + * wait until it's time to display next frame + */ + + if (img) + frame_duration = img->duration; + + next_frame_pts += frame_duration; #ifdef VIDEO_OUT_LOG - printf ("video_out : passing to video driver, image with pts = %d\n", pts); + printf ("video_out: next_frame_pts is %lld\n", next_frame_pts); #endif + + do { + vpts = this->metronom->get_current_time (this->metronom); - if (this->overlay_source) { - /* This is the only way for the overlay manager to get pts values - * for flushing it's buffers. So don't remove it! */ - xine_profiler_start_count (prof_spu_blend); + usec_to_sleep = (next_frame_pts - vpts) * 100 / 9; - this->overlay_source->multiple_overlay_blend (this->overlay_source, img->PTS, - this->driver, img, - this->video_loop_running && this->overlay_enabled); - xine_profiler_stop_count (prof_spu_blend); - } - - this->driver->display_frame (this->driver, img); + printf ("video_out: %lld usec to sleep at master vpts %lld\n", + usec_to_sleep, vpts); + + if (usec_to_sleep>0) + xine_usec_sleep (usec_to_sleep); - xine_profiler_stop_count (prof_video_out); + } while (usec_to_sleep > 0); } + /* * throw away undisplayed frames */ @@ -596,29 +716,32 @@ static void *video_out_loop (void *this_gen) { img = this->display_img_buf_queue->first; } - if( img_backup ) { - pthread_mutex_lock (&img_backup->mutex); + if (this->img_backup) { + pthread_mutex_lock (&this->img_backup->mutex); - img_backup->display_locked = 0; - if( !img_backup->decoder_locked ) - vo_append_to_img_buf_queue (this->free_img_buf_queue, img_backup); + this->img_backup->display_locked = 0; + if (!this->img_backup->decoder_locked) + vo_append_to_img_buf_queue (this->free_img_buf_queue, this->img_backup); - pthread_mutex_unlock (&img_backup->mutex); + pthread_mutex_unlock (&this->img_backup->mutex); } pthread_exit(NULL); } -static uint32_t vo_get_capabilities (vo_instance_t *this) { +static uint32_t vo_get_capabilities (vo_instance_t *this_gen) { + vos_t *this = (vos_t *) this_gen; return this->driver->get_capabilities (this->driver); } -static vo_frame_t * vo_duplicate_frame( vo_instance_t *this, vo_frame_t *img ) { +static vo_frame_t * vo_duplicate_frame( vo_instance_t *this_gen, vo_frame_t *img ) { + vo_frame_t *dupl; - int image_size; + /* vos_t *this = (vos_t *) this_gen; */ + int image_size; - dupl = vo_get_frame( this, img->width, img->height, img->ratio, - img->format, img->duration, VO_BOTH_FIELDS ); + dupl = vo_get_frame (this_gen, img->width, img->height, img->ratio, + img->format, VO_BOTH_FIELDS ); pthread_mutex_lock (&dupl->mutex); @@ -643,7 +766,10 @@ static vo_frame_t * vo_duplicate_frame( vo_instance_t *this, vo_frame_t *img ) { } dupl->bad_frame = 0; - dupl->PTS = dupl->SCR = 0; + dupl->pts = 0; + dupl->vpts = 0; + dupl->scr = 0; + dupl->duration = img->duration; /* Support copy; Dangerous, since some decoders may use a source that's * not dupl->base. It's up to the copy implementation to check for NULL */ @@ -683,14 +809,18 @@ static vo_frame_t * vo_duplicate_frame( vo_instance_t *this, vo_frame_t *img ) { return dupl; } -static void vo_open (vo_instance_t *this) { +static void vo_open (vo_instance_t *this_gen) { + + vos_t *this = (vos_t *) this_gen; - this->decoder_started_flag = 0; this->video_opened = 1; + this->last_delivery_pts = 0; } -static void vo_close (vo_instance_t *this) { - +static void vo_close (vo_instance_t *this_gen) { + + vos_t *this = (vos_t *) this_gen; + /* this will make sure all hide events were processed */ if (this->overlay_source) this->overlay_source->flush_events (this->overlay_source); @@ -698,7 +828,8 @@ static void vo_close (vo_instance_t *this) { this->video_opened = 0; } -static void vo_free_img_buffers (vo_instance_t *this) { +static void vo_free_img_buffers (vo_instance_t *this_gen) { + vos_t *this = (vos_t *) this_gen; vo_frame_t *img; while (this->free_img_buf_queue->first) { @@ -712,163 +843,45 @@ static void vo_free_img_buffers (vo_instance_t *this) { } } -static void vo_exit (vo_instance_t *this) { +static void vo_exit (vo_instance_t *this_gen) { + + vos_t *this = (vos_t *) this_gen; printf ("video_out: vo_exit...\n"); if (this->video_loop_running) { void *p; this->video_loop_running = 0; - this->video_paused = 0; pthread_join (this->video_thread, &p); } - vo_free_img_buffers (this); + vo_free_img_buffers (this_gen); this->driver->exit (this->driver); printf ("video_out: vo_exit... done\n"); } -static void vo_frame_displayed (vo_frame_t *img) { - - pthread_mutex_lock (&img->mutex); - - img->driver_locked = 0; - - if (!img->decoder_locked) { - vo_append_to_img_buf_queue (img->instance->free_img_buf_queue, img); - } - - pthread_mutex_unlock (&img->mutex); -} - -static void vo_frame_free (vo_frame_t *img) { - - pthread_mutex_lock (&img->mutex); - img->decoder_locked = 0; - - if (!img->display_locked && !img->driver_locked ) { - vo_append_to_img_buf_queue (img->instance->free_img_buf_queue, img); - } - - pthread_mutex_unlock (&img->mutex); -} - -static vo_frame_t *vo_get_last_frame (vo_instance_t *this) { +static vo_frame_t *vo_get_last_frame (vo_instance_t *this_gen) { + vos_t *this = (vos_t *) this_gen; return this->last_frame; } -static int vo_frame_draw (vo_frame_t *img) { - - vo_instance_t *this = img->instance; - int32_t diff; - uint32_t cur_vpts; - uint32_t pic_vpts ; - int frames_to_skip; - - pic_vpts = this->metronom->got_video_frame (this->metronom, img->PTS, img->SCR); - -#ifdef VIDEO_OUT_LOG - printf ("video_out : got image %d. vpts for picture is %d (pts was %d)\n", - img, pic_vpts, img->PTS); -#endif - - img->PTS = pic_vpts; - this->num_frames_delivered++; - - cur_vpts = this->metronom->get_current_time(this->metronom); - this->last_draw_vpts = cur_vpts; - - diff = pic_vpts - cur_vpts; - frames_to_skip = ((-1 * diff) / this->pts_per_frame + 3) * 2; - -#ifdef VIDEO_OUT_LOG - printf ("video_out : delivery diff : %d\n",diff); -#endif - - if (img->display_locked) { - LOG_MSG(this->xine, _("video_out : ALERT! frame is already locked for displaying\n")); - return frames_to_skip; - } - - if (cur_vpts>0) { - - if (diff<(-1 * this->pts_per_half_frame) && img->drawn != 2 ) { - - this->num_frames_discarded++; -#ifdef VIDEO_OUT_LOG - printf ("video_out : frame rejected, %d frames to skip\n", frames_to_skip); -#endif - - LOG_MSG(this->xine, _("video_out: rejected, %d frames to skip\n"), frames_to_skip); - - pthread_mutex_lock (&img->mutex); - img->display_locked = 0; - pthread_mutex_unlock (&img->mutex); - - vo_frame_displayed (img); - - this->last_frame = img; - - return frames_to_skip; - - } - } /* else: we are probably in precaching mode */ - - if (!img->bad_frame) { - /* - * put frame into FIFO-Buffer - */ - -#ifdef VIDEO_OUT_LOG - printf ("video_out : frame is ok => appending to display buffer\n"); -#endif - - this->last_frame = img; - - pthread_mutex_lock (&img->mutex); - img->display_locked = 1; - pthread_mutex_unlock (&img->mutex); - - vo_append_to_img_buf_queue (this->display_img_buf_queue, img); - - } else { - this->num_frames_skipped++; - - pthread_mutex_lock (&img->mutex); - img->display_locked = 0; - pthread_mutex_unlock (&img->mutex); - - vo_frame_displayed (img); - } - - /* - * performance measurement - */ - - if (this->num_frames_delivered>199) { - LOG_MSG_STDERR(this->xine, - _("%d frames delivered, %d frames skipped, %d frames discarded\n"), - this->num_frames_delivered, this->num_frames_skipped, this->num_frames_discarded); +/* + * overlay stuff + */ - this->num_frames_delivered = 0; - this->num_frames_discarded = 0; - this->num_frames_skipped = 0; - } - - return frames_to_skip; +static video_overlay_instance_t *vo_get_overlay_instance (vo_instance_t *this_gen) { + vos_t *this = (vos_t *) this_gen; + return this->overlay_source; } -static void vo_enable_overlay (vo_instance_t *this, int overlay_enabled) { +static void vo_enable_overlay (vo_instance_t *this_gen, int overlay_enabled) { + vos_t *this = (vos_t *) this_gen; this->overlay_enabled = overlay_enabled; } -static void vo_decoder_started (vo_instance_t *this) { - this->decoder_started_flag = 1; -} - static uint16_t gzread_i16(gzFile *fp) { uint16_t ret; ret = gzgetc(fp) << 8 ; @@ -880,28 +893,28 @@ static uint16_t gzread_i16(gzFile *fp) { vo_instance_t *vo_new_instance (vo_driver_t *driver, xine_t *xine) { - vo_instance_t *this; + vos_t *this; int i; char pathname[LOGO_PATH_MAX]; pthread_attr_t pth_attrs; int err; gzFile *fp; + this = xine_xmalloc (sizeof (vos_t)) ; - this = xine_xmalloc (sizeof (vo_instance_t)) ; this->driver = driver; this->xine = xine; this->metronom = xine->metronom; - this->open = vo_open; - this->get_frame = vo_get_frame; - this->duplicate_frame = vo_duplicate_frame; - this->get_last_frame = vo_get_last_frame; - this->close = vo_close; - this->exit = vo_exit; - this->get_capabilities = vo_get_capabilities; - this->enable_ovl = vo_enable_overlay; - this->decoder_started = vo_decoder_started; + this->vo.open = vo_open; + this->vo.get_frame = vo_get_frame; + this->vo.duplicate_frame = vo_duplicate_frame; + this->vo.get_last_frame = vo_get_last_frame; + this->vo.close = vo_close; + this->vo.exit = vo_exit; + this->vo.get_capabilities = vo_get_capabilities; + this->vo.enable_ovl = vo_enable_overlay; + this->vo.get_overlay_instance = vo_get_overlay_instance; this->num_frames_delivered = 0; this->num_frames_skipped = 0; @@ -909,9 +922,9 @@ vo_instance_t *vo_new_instance (vo_driver_t *driver, xine_t *xine) { this->free_img_buf_queue = vo_new_img_buf_queue (); this->display_img_buf_queue = vo_new_img_buf_queue (); this->video_loop_running = 0; - this->video_paused = 0; - this->pts_per_frame = 6000; - this->pts_per_half_frame = 3000; + + this->img_backup = NULL; + this->backup_is_logo = 0; this->overlay_source = video_overlay_new_instance(); this->overlay_source->init (this->overlay_source); @@ -922,7 +935,7 @@ vo_instance_t *vo_new_instance (vo_driver_t *driver, xine_t *xine) { img = driver->alloc_frame (driver) ; - img->instance = this; + img->instance = &this->vo; img->free = vo_frame_free ; img->displayed = vo_frame_displayed; img->draw = vo_frame_draw; @@ -961,7 +974,6 @@ vo_instance_t *vo_new_instance (vo_driver_t *driver, xine_t *xine) { */ this->video_loop_running = 1; - this->decoder_started_flag = 0; this->video_opened = 0; pthread_attr_init(&pth_attrs); @@ -976,10 +988,7 @@ vo_instance_t *vo_new_instance (vo_driver_t *driver, xine_t *xine) { printf (_("video_out: sorry, this should not happen. please restart xine.\n")); exit(1); } else - LOG_MSG(this->xine, _("video_out : thread created\n")); + LOG_MSG(this->xine, _("video_out: thread created\n")); - return this; + return &this->vo; } - - - diff --git a/src/xine-engine/video_out.h b/src/xine-engine/video_out.h index 7738e8ad8..a75547236 100644 --- a/src/xine-engine/video_out.h +++ b/src/xine-engine/video_out.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000-2001 the xine project + * Copyright (C) 2000-2002 the xine project * * This file is part of xine, a free video player. * @@ -17,11 +17,19 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: video_out.h,v 1.39 2002/01/24 23:09:54 guenter Exp $ + * $Id: video_out.h,v 1.40 2002/02/09 07:13:24 guenter Exp $ * * * xine version of video_out.h * + * vo_frame : frame containing yuv data and timing info, + * transferred between video_decoder and video_output + * + * vo_driver : lowlevel, platform-specific video output code + * + * vo_instance : generic frame_handling code, uses + * a vo_driver for output + * */ #ifndef HAVE_VIDEO_OUT_H @@ -38,6 +46,7 @@ extern "C" { #include <inttypes.h> #include <pthread.h> +#if 0 #if defined(XINE_COMPILE) #include "configfile.h" #include "metronom.h" @@ -47,6 +56,7 @@ extern "C" { #include "xine/metronom.h" #include "xine/buffer.h" #endif +#endif #define VIDEO_OUT_PLUGIN_IFACE_VERSION 1 @@ -58,46 +68,50 @@ typedef struct img_buf_fifo_s img_buf_fifo_t; typedef struct vo_overlay_s vo_overlay_t; typedef struct video_overlay_instance_s video_overlay_instance_t; typedef struct xine_s xine_t; +typedef struct vo_private_s vo_private_t; /* public part, video drivers may add private fields */ struct vo_frame_s { struct vo_frame_s *next; - uint32_t PTS; - uint32_t pts_corrector; /* Repeat first field tricks */ - uint32_t SCR; - int bad_frame; /* e.g. frame skipped or based on skipped frame */ - int drawn; - uint8_t *base[3]; + int64_t pts; /* presentation time stamp (1/90000 sec) */ + int64_t vpts; /* virtual pts, generated by metronom */ + int64_t pts_corrector; /* used for pepeat first field tricks */ + int64_t scr; /* system clock reference (discont. detection) */ + int bad_frame; /* e.g. frame skipped or based on skipped frame */ + int duration; /* frame length in time, in 1/90000 sec */ + /* yv12 (planar) base[0]: y, base[1]: u, base[2]: v */ + /* yuy2 (interleaved) base[0]: yuyv..., base[1]: --, base[2]: -- */ + uint8_t *base[3]; - /* additional information to be able to duplicate frames: */ + /* info that can be used for interlaced output (e.g. tv-out) */ + int top_field_first; + int repeat_first_field; + + /* additional information to be able to duplicate frames: */ int width, height; - int ratio, format; - int duration; - int aspect_ratio; - int frame_rate_code; - int progressive_sequence; - int top_field_first; - int repeat_first_field; - int progressive_frame; - int picture_coding_type; - int bitrate; + int ratio; /* aspect ratio, codes see below */ + int format; /* IMGFMT_YV12 or IMGFMT_RGB */ + + int drawn; /* used by decoder, frame has already been drawn */ int display_locked, decoder_locked, driver_locked; pthread_mutex_t mutex; /* so the various locks will be serialized */ - vo_instance_t *instance; + /* "backward" references to where this frame originates from */ + vo_instance_t *instance; + vo_driver_t *driver; /* * member functions */ - /* this frame is no longer used by decoder */ + /* this frame is no longer used by the decoder */ void (*free) (vo_frame_t *vo_img); - /* tell video driver to copy/convert a slice of this frame */ + /* tell video driver to copy/convert a slice of this frame, may be NULL */ void (*copy) (vo_frame_t *vo_img, uint8_t **src); /* tell video driver that the decoder starts a new field */ @@ -128,13 +142,11 @@ struct vo_instance_s { * height == height of video to display. * ratio == aspect ration information * format == FOURCC descriptor of image format - * duration == frame duration in 1/90000 sec * flags == field/prediction flags */ vo_frame_t* (*get_frame) (vo_instance_t *this, uint32_t width, uint32_t height, int ratio_code, - int format, uint32_t duration, - int flags); + int format, int flags); vo_frame_t* (*get_last_frame) (vo_instance_t *this); @@ -146,46 +158,18 @@ struct vo_instance_s { /* overlay stuff */ void (*enable_ovl) (vo_instance_t *this, int ovl_enable); - video_overlay_instance_t *overlay_source; - int overlay_enabled; - /* this is just a hint to video_out to detect single frame streams */ - void (*decoder_started) (vo_instance_t *this); - /* video driver is no longer used by decoder => close */ void (*close) (vo_instance_t *this); /* called on xine exit */ void (*exit) (vo_instance_t *this); - /* private stuff */ - - vo_driver_t *driver; - metronom_t *metronom; - xine_t *xine; - - img_buf_fifo_t *free_img_buf_queue; - img_buf_fifo_t *display_img_buf_queue; - - vo_frame_t *last_frame; - - int video_loop_running; - int video_opened; - int video_paused; - pthread_t video_thread; - - int pts_per_half_frame; - int pts_per_frame; - - int num_frames_delivered; - int num_frames_skipped; - int num_frames_discarded; + /* get overlay instance (overlay source) */ + video_overlay_instance_t* (*get_overlay_instance) (vo_instance_t *this); - int decoder_started_flag; - uint32_t last_draw_vpts; + /* private stuff can be added here */ - int logo_w, logo_h; - uint8_t *logo_yuy2; } ; /* constants for the get/set property functions */ @@ -225,7 +209,7 @@ struct vo_instance_s { #define IMGFMT_YV12 0x32315659 #define IMGFMT_YUY2 (('2'<<24)|('Y'<<16)|('U'<<8)|'Y') -#define IMGFMT_RGB (('R'<<24)|('G'<<16)|('B'<<8)) +/*#define IMGFMT_RGB (('R'<<24)|('G'<<16)|('B'<<8)) unused */ /* possible ratios for the VO_PROP_ASPECT_RATIO call */ diff --git a/src/xine-engine/video_overlay.h b/src/xine-engine/video_overlay.h index 5752642c9..08bf6e0a6 100644 --- a/src/xine-engine/video_overlay.h +++ b/src/xine-engine/video_overlay.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: video_overlay.h,v 1.4 2002/01/05 19:09:55 jcdutton Exp $ + * $Id: video_overlay.h,v 1.5 2002/02/09 07:13:24 guenter Exp $ * */ @@ -32,33 +32,33 @@ #define CLUT_Y_CR_CB_INIT(_y,_cr,_cb) { (_cb), (_cr), (_y) } #endif -#define MAX_OBJECTS 50 -#define MAX_EVENTS 50 -#define MAX_SHOWING 5 +#define MAX_OBJECTS 50 +#define MAX_EVENTS 50 +#define MAX_SHOWING 5 -#define EVENT_NULL 0 -#define EVENT_SHOW_SPU 1 -#define EVENT_HIDE_SPU 2 -#define EVENT_HIDE_MENU 3 -#define EVENT_MENU_SPU 4 -#define EVENT_MENU_BUTTON 5 -#define EVENT_DELETE_RESOURCE 6 /* Maybe release handle will do this */ -#define EVENT_SHOW_OSD 7 /* Not yet implemented */ -#define EVENT_FREE_HANDLE 8 /* Frees a handle, previous allocated via get_handle */ +#define EVENT_NULL 0 +#define EVENT_SHOW_SPU 1 +#define EVENT_HIDE_SPU 2 +#define EVENT_HIDE_MENU 3 +#define EVENT_MENU_SPU 4 +#define EVENT_MENU_BUTTON 5 +#define EVENT_DELETE_RESOURCE 6 /* Maybe release handle will do this */ +#define EVENT_SHOW_OSD 7 /* Not yet implemented */ +#define EVENT_FREE_HANDLE 8 /* Frees a handle, previous allocated via get_handle */ typedef struct video_overlay_object_s { - int32_t handle; /* Used to match Show and Hide events. */ - uint32_t object_type; /* 0=Subtitle, 1=Menu */ - uint32_t pts; /* Needed for Menu button compares */ - vo_overlay_t *overlay; /* The image data. */ + int32_t handle; /* Used to match Show and Hide events. */ + uint32_t object_type; /* 0=Subtitle, 1=Menu */ + uint32_t pts; /* Needed for Menu button compares */ + vo_overlay_t *overlay; /* The image data. */ uint32_t palette_type; /* 1 Y'CrCB, 2 R'G'B' */ - uint32_t *palette; /* If NULL, no palette contained in this event. */ + uint32_t *palette; /* If NULL, no palette contained in this event. */ } video_overlay_object_t; /* This will hold all details of an event item, needed for event queue to function */ typedef struct video_overlay_event_s { uint32_t event_type; /* Show SPU, Show OSD, Hide etc. */ - uint32_t vpts; /* Time when event will action. 0 means action now */ + uint32_t vpts; /* Time when event will action. 0 means action now */ /* Once video_out blend_yuv etc. can take rle_elem_t with Colour, blend and length information. * we can remove clut and blend from this structure. * This will allow for many more colours for OSD. diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c index 5f8e9be8d..1329dde12 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.102 2002/02/01 09:59:08 f1rmb Exp $ + * $Id: xine.c,v 1.103 2002/02/09 07:13:24 guenter Exp $ * * top-level xine functions * @@ -159,7 +159,7 @@ void xine_stop_internal (xine_t *this) { this->metronom->set_speed (this->metronom, SPEED_NORMAL); this->speed = SPEED_NORMAL; - this->video_out->video_paused = 0; + if( this->audio_out ) this->audio_out->audio_paused = 0; @@ -298,11 +298,6 @@ int xine_play (xine_t *this, char *mrl, this->cur_input_plugin->stop(this->cur_input_plugin); } - /* this will make output threads discard about everything - (seeking should be faster!) */ - this->metronom->adjust_clock(this->metronom, - this->metronom->get_current_time(this->metronom) + 30 * 90000 ); - this->status = XINE_STOP; } @@ -373,7 +368,7 @@ int xine_play (xine_t *this, char *mrl, strncpy (this->cur_mrl, mrl, 1024); this->metronom->set_speed (this->metronom, SPEED_NORMAL); - this->video_out->video_paused = 0; + if( this->audio_out ) this->audio_out->audio_paused = 0; this->speed = SPEED_NORMAL; @@ -504,7 +499,7 @@ xine_t *xine_init (vo_driver_t *vo, this->video_out = vo_new_instance (vo, this); video_decoder_init (this); - this->osd_renderer = osd_renderer_init( this->video_out->overlay_source, config ); + this->osd_renderer = osd_renderer_init (this->video_out->get_overlay_instance (this->video_out), config ); this->osd = this->osd_renderer->new_object (this->osd_renderer, 300, 100); this->osd_renderer->set_font (this->osd, "cetus", 24); @@ -704,7 +699,6 @@ void xine_set_speed (xine_t *this, int speed) { this->metronom->set_speed (this->metronom, speed); - this->video_out->video_paused = (speed == SPEED_PAUSE); /* see coment on audio_out loop about audio_paused */ if( this->audio_out ) this->audio_out->audio_paused = (speed != SPEED_NORMAL) + |