diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/xine-engine/post.c | 13 | ||||
-rw-r--r-- | src/xine-engine/video_decoder.c | 10 | ||||
-rw-r--r-- | src/xine-engine/video_out.c | 118 | ||||
-rw-r--r-- | src/xine-engine/video_out.h | 3 | ||||
-rw-r--r-- | src/xine-engine/video_overlay.h | 2 | ||||
-rw-r--r-- | src/xine-engine/xine.c | 96 | ||||
-rw-r--r-- | src/xine-engine/xine_internal.h | 9 |
7 files changed, 236 insertions, 15 deletions
diff --git a/src/xine-engine/post.c b/src/xine-engine/post.c index 6ae96e982..0dba50c82 100644 --- a/src/xine-engine/post.c +++ b/src/xine-engine/post.c @@ -149,6 +149,14 @@ static void post_video_flush(xine_video_port_t *port_gen) { if (port->port_lock) pthread_mutex_unlock(port->port_lock); } +static void post_video_trigger_drawing(xine_video_port_t *port_gen) { + post_video_port_t *port = (post_video_port_t *)port_gen; + + if (port->port_lock) pthread_mutex_lock(port->port_lock); + port->original_port->trigger_drawing(port->original_port); + if (port->port_lock) pthread_mutex_unlock(port->port_lock); +} + static int post_video_status(xine_video_port_t *port_gen, xine_stream_t *stream, int *width, int *height, int64_t *img_duration) { post_video_port_t *port = (post_video_port_t *)port_gen; @@ -192,6 +200,7 @@ static int post_video_rewire(xine_post_out_t *output_gen, void *data) { if (!new_port) return 0; + this->running_ticket->lock_port_rewiring(this->running_ticket, -1); this->running_ticket->revoke(this->running_ticket, 1); if (input_port->original_port->status(input_port->original_port, input_port->stream, @@ -202,6 +211,7 @@ static int post_video_rewire(xine_post_out_t *output_gen, void *data) { input_port->original_port = new_port; this->running_ticket->issue(this->running_ticket, 1); + this->running_ticket->unlock_port_rewiring(this->running_ticket); return 1; } @@ -223,6 +233,7 @@ post_video_port_t *_x_post_intercept_video_port(post_plugin_t *post, xine_video_ port->new_port.exit = post_video_exit; port->new_port.get_overlay_manager = post_video_get_overlay_manager; port->new_port.flush = post_video_flush; + port->new_port.trigger_drawing = post_video_trigger_drawing; port->new_port.status = post_video_status; port->new_port.get_property = post_video_get_property; port->new_port.set_property = post_video_set_property; @@ -680,6 +691,7 @@ static int post_audio_rewire(xine_post_out_t *output_gen, void *data) { if (!new_port) return 0; + this->running_ticket->lock_port_rewiring(this->running_ticket, -1); this->running_ticket->revoke(this->running_ticket, 1); if (input_port->original_port->status(input_port->original_port, input_port->stream, @@ -690,6 +702,7 @@ static int post_audio_rewire(xine_post_out_t *output_gen, void *data) { input_port->original_port = new_port; this->running_ticket->issue(this->running_ticket, 1); + this->running_ticket->unlock_port_rewiring(this->running_ticket); return 1; } diff --git a/src/xine-engine/video_decoder.c b/src/xine-engine/video_decoder.c index fee75ec76..3d39b4550 100644 --- a/src/xine-engine/video_decoder.c +++ b/src/xine-engine/video_decoder.c @@ -28,6 +28,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> #define XINE_ENGINE_INTERNAL @@ -110,6 +111,15 @@ static void *video_decoder_loop (void *stream_gen) { int prof_video_decode = -1; int prof_spu_decode = -1; uint32_t buftype_unknown = 0; + +#ifndef WIN32 + /* nice(-value) will fail silently for normal users. + * however when running as root this may provide smoother + * playback. follow the link for more information: + * http://cambuca.ldhs.cetuc.puc-rio.br/~miguel/multimedia_sim/ + */ + nice(-1); +#endif /* WIN32 */ if (prof_video_decode == -1) prof_video_decode = xine_profiler_allocate_slot ("video decoder"); diff --git a/src/xine-engine/video_out.c b/src/xine-engine/video_out.c index 2a3ee1980..eeade3f48 100644 --- a/src/xine-engine/video_out.c +++ b/src/xine-engine/video_out.c @@ -71,6 +71,7 @@ typedef struct { vo_frame_t *first; vo_frame_t *last; int num_buffers; + int num_buffers_max; int locked_for_read; pthread_mutex_t mutex; @@ -128,9 +129,14 @@ typedef struct { int current_width, current_height; int64_t current_duration; + int frame_drop_limit_max; int frame_drop_limit; int frame_drop_cpt; + int frame_drop_suggested; int crop_left, crop_right, crop_top, crop_bottom; + pthread_mutex_t trigger_drawing_mutex; + pthread_cond_t trigger_drawing_cond; + int trigger_drawing; } vos_t; @@ -144,9 +150,11 @@ static img_buf_fifo_t *vo_new_img_buf_queue () { queue = (img_buf_fifo_t *) xine_xmalloc (sizeof (img_buf_fifo_t)); if( queue ) { - queue->first = NULL; - queue->last = NULL; - queue->num_buffers = 0; + queue->first = NULL; + queue->last = NULL; + queue->num_buffers = 0; + queue->num_buffers_max = 0; + queue->locked_for_read = 0; pthread_mutex_init (&queue->mutex, NULL); pthread_cond_init (&queue->not_empty, NULL); @@ -173,6 +181,8 @@ static void vo_append_to_img_buf_queue_int (img_buf_fifo_t *queue, } queue->num_buffers++; + if (queue->num_buffers_max < queue->num_buffers) + queue->num_buffers_max = queue->num_buffers; pthread_cond_signal (&queue->not_empty); } @@ -213,14 +223,15 @@ static vo_frame_t *vo_remove_from_img_buf_queue_int (img_buf_fifo_t *queue, int if( width && height ) { if( !img ) { - if( queue->num_buffers == 1 && !blocking) { + if( queue->num_buffers == 1 && !blocking && queue->num_buffers_max > 8) { /* non-blocking and only a single frame on fifo with different * format -> ignore it (give another chance of a frame format hit) + * only if we have a lot of buffers at all. */ lprintf("frame format mismatch - will wait another frame\n"); } else { - /* we have at least 2 frames on fifo but they don't match -> - * give up. return whatever we got. + /* we have just a limited number of buffers or at least 2 frames + * on fifo but they don't match -> give up. return whatever we got. */ img = queue->first; lprintf("frame format miss (%d/%d)\n", i, queue->num_buffers); @@ -467,28 +478,46 @@ static int vo_frame_draw (vo_frame_t *img, xine_stream_t *stream) { duration = img->duration; /* Frame dropping slow start: - * The engine starts to drop frames if there is less than frame_drop_limit + * The engine starts to drop frames if there are less than frame_drop_limit * frames in advance. There might be a problem just after a seek because * there is no frame in advance yet. * The following code increases progressively the frame_drop_limit (-2 -> 3) * after a seek to give a chance to the engine to display the first frames - * smootly before starting to drop frames if the decoder is really too + * smoothly before starting to drop frames if the decoder is really too * slow. + * The above numbers are the result of frame_drop_limit_max beeing 3. They + * will be (-4 -> 1) when frame_drop_limit_max is only 1. This maximum value + * depends on the number of video buffers which the output device provides. */ if (stream && stream->first_frame_flag == 2) this->frame_drop_cpt = 10; if (this->frame_drop_cpt) { - this->frame_drop_limit = 3 - (this->frame_drop_cpt / 2); + this->frame_drop_limit = this->frame_drop_limit_max - (this->frame_drop_cpt / 2); this->frame_drop_cpt--; } frames_to_skip = ((-1 * diff) / duration + this->frame_drop_limit) * 2; /* do not skip decoding until output fifo frames are consumed */ - if (this->display_img_buf_queue->num_buffers > this->frame_drop_limit || + if (this->display_img_buf_queue->num_buffers >= this->frame_drop_limit || frames_to_skip < 0) frames_to_skip = 0; + /* Do not drop frames immediately, but remember this as suggestion and give + * decoder a further chance to supply frames. + * This avoids unnecessary frame drops in situations where there is only + * a very little number of image buffers, e. g. when using xxmc. + */ + if (this->frame_drop_suggested && frames_to_skip == 0) + this->frame_drop_suggested = 0; + + if (frames_to_skip > 0) { + if (!this->frame_drop_suggested) { + this->frame_drop_suggested = 1; + frames_to_skip = 0; + } + } + lprintf ("delivery diff : %" PRId64 ", current vpts is %" PRId64 ", %d frames to skip\n", diff, cur_vpts, frames_to_skip); @@ -1043,6 +1072,32 @@ static void check_redraw_needed (vos_t *this, int64_t vpts) { this->redraw_needed = 1; } +static int interruptable_sleep(vos_t *this, int usec_to_sleep) +{ + int timedout = 0; + + struct timeval now; + gettimeofday(&now, 0); + + pthread_mutex_lock (&this->trigger_drawing_mutex); + if (!this->trigger_drawing) { + struct timespec abstime; + abstime.tv_sec = now.tv_sec + usec_to_sleep / 1000000; + abstime.tv_nsec = now.tv_usec * 1000 + (usec_to_sleep % 1000000) * 1000; + + if (abstime.tv_nsec > 1000000000) { + abstime.tv_nsec -= 1000000000; + abstime.tv_sec++; + } + + timedout = pthread_cond_timedwait(&this->trigger_drawing_cond, &this->trigger_drawing_mutex, &abstime); + } + this->trigger_drawing = 0; + pthread_mutex_unlock (&this->trigger_drawing_mutex); + + return timedout; +} + /* special loop for paused mode * needed to update screen due overlay changes, resize, window * movement, brightness adjusting etc. @@ -1088,7 +1143,7 @@ static void paused_loop( vos_t *this, int64_t vpts ) } pthread_mutex_unlock( &this->free_img_buf_queue->mutex ); - xine_usec_sleep (20000); + interruptable_sleep(this, 20000); pthread_mutex_lock( &this->free_img_buf_queue->mutex ); } @@ -1218,7 +1273,10 @@ static void *video_out_loop (void *this_gen) { "video_out: vpts/clock error, next_vpts=%" PRId64 " cur_vpts=%" PRId64 "\n", next_frame_vpts,vpts); if (usec_to_sleep > 0) - xine_usec_sleep (usec_to_sleep); + { + if (0 == interruptable_sleep(this, usec_to_sleep)) + break; + } if (this->discard_frames) break; @@ -1601,6 +1659,9 @@ static void vo_exit (xine_video_port_t *this_gen) { free (this->free_img_buf_queue); free (this->display_img_buf_queue); + pthread_cond_destroy(&this->trigger_drawing_cond); + pthread_mutex_destroy(&this->trigger_drawing_mutex); + free (this); } @@ -1670,6 +1731,15 @@ static void vo_flush (xine_video_port_t *this_gen) { } } +static void vo_trigger_drawing (xine_video_port_t *this_gen) { + vos_t *this = (vos_t *) this_gen; + + pthread_mutex_lock (&this->trigger_drawing_mutex); + this->trigger_drawing = 1; + pthread_cond_signal (&this->trigger_drawing_cond); + pthread_mutex_unlock (&this->trigger_drawing_mutex); +} + /* crop_frame() will allocate a new frame to copy in the given image * while cropping. maybe someday this will be an automatic post plugin. */ @@ -1765,6 +1835,7 @@ xine_video_port_t *_x_vo_new_port (xine_t *xine, vo_driver_t *driver, int grabon this->vo.enable_ovl = vo_enable_overlay; this->vo.get_overlay_manager = vo_get_overlay_manager; this->vo.flush = vo_flush; + this->vo.trigger_drawing = vo_trigger_drawing; this->vo.get_property = vo_get_property; this->vo.set_property = vo_set_property; this->vo.status = vo_status; @@ -1784,8 +1855,6 @@ xine_video_port_t *_x_vo_new_port (xine_t *xine, vo_driver_t *driver, int grabon this->overlay_source->init (this->overlay_source); this->overlay_enabled = 1; - this->frame_drop_limit = 3; - this->frame_drop_cpt = 0; /* default number of video frames from config */ num_frame_buffers = xine->config->register_num (xine->config, @@ -1806,6 +1875,24 @@ xine_video_port_t *_x_vo_new_port (xine_t *xine, vo_driver_t *driver, int grabon if (num_frame_buffers<5) num_frame_buffers = 5; + /* Choose a frame_drop_limit which matches num_frame_buffers. + * xxmc for example supplies only 8 buffers. 2 are occupied by + * MPEG2 decoding, further 2 for displaying and the remaining 4 can + * hardly be filled all the time. + * The below constants reserve buffers for decoding, displaying and + * buffer fluctuation. + * A frame_drop_limit_max below 1 will disable frame drops at all. + */ + this->frame_drop_limit_max = num_frame_buffers - 2 - 2 - 1; + if (this->frame_drop_limit_max < 1) + this->frame_drop_limit_max = 1; + else if (this->frame_drop_limit_max > 3) + this->frame_drop_limit_max = 3; + + this->frame_drop_limit = this->frame_drop_limit_max; + this->frame_drop_cpt = 0; + this->frame_drop_suggested = 0; + this->extra_info_base = calloc (num_frame_buffers, sizeof(extra_info_t)); @@ -1842,6 +1929,9 @@ xine_video_port_t *_x_vo_new_port (xine_t *xine, vo_driver_t *driver, int grabon "were not scheduled for display in time, xine sends a notification."), 20, NULL, NULL); + pthread_mutex_init(&this->trigger_drawing_mutex, NULL); + pthread_cond_init(&this->trigger_drawing_cond, NULL); + this->trigger_drawing = 0; if (grabonly) { diff --git a/src/xine-engine/video_out.h b/src/xine-engine/video_out.h index 9bfd2b6dd..bd169acfe 100644 --- a/src/xine-engine/video_out.h +++ b/src/xine-engine/video_out.h @@ -206,6 +206,9 @@ struct xine_video_port_s { /* flush video_out fifo */ void (*flush) (xine_video_port_t *self); + /* trigger immediate drawing */ + void (*trigger_drawing) (xine_video_port_t *self); + /* Get/Set video property * * See VO_PROP_* bellow diff --git a/src/xine-engine/video_overlay.h b/src/xine-engine/video_overlay.h index d8711363b..5e3455461 100644 --- a/src/xine-engine/video_overlay.h +++ b/src/xine-engine/video_overlay.h @@ -38,7 +38,7 @@ #define MAX_OBJECTS 50 #define MAX_EVENTS 50 -#define MAX_SHOWING 16 +#define MAX_SHOWING (5 + 16) #define OVERLAY_EVENT_NULL 0 #define OVERLAY_EVENT_SHOW 1 diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c index d6fd87be4..3af3f8b13 100644 --- a/src/xine-engine/xine.c +++ b/src/xine-engine/xine.c @@ -241,8 +241,37 @@ static void ticket_revoke(xine_ticket_t *this, int atomic) { pthread_mutex_unlock(&this->revoke_lock); } +static int ticket_lock_port_rewiring(xine_ticket_t *this, int ms_timeout) { + + if (ms_timeout >= 0) { + struct timespec abstime; + + struct timeval now; + gettimeofday(&now, 0); + + abstime.tv_sec = now.tv_sec + ms_timeout / 1000; + abstime.tv_nsec = now.tv_usec * 1000 + (ms_timeout % 1000) * 1e6; + + if (abstime.tv_nsec > 1e9) { + abstime.tv_nsec -= 1e9; + abstime.tv_sec++; + } + + return (0 == pthread_mutex_timedlock(&this->port_rewiring_lock, &abstime)); + } + + pthread_mutex_lock(&this->port_rewiring_lock); + return 1; +} + +static void ticket_unlock_port_rewiring(xine_ticket_t *this) { + + pthread_mutex_unlock(&this->port_rewiring_lock); +} + static void ticket_dispose(xine_ticket_t *this) { + pthread_mutex_destroy(&this->port_rewiring_lock); pthread_mutex_destroy(&this->lock); pthread_mutex_destroy(&this->revoke_lock); pthread_cond_destroy(&this->issued); @@ -263,10 +292,13 @@ static xine_ticket_t *ticket_init(void) { port_ticket->renew = ticket_renew; port_ticket->issue = ticket_issue; port_ticket->revoke = ticket_revoke; + port_ticket->lock_port_rewiring = ticket_lock_port_rewiring; + port_ticket->unlock_port_rewiring = ticket_unlock_port_rewiring; port_ticket->dispose = ticket_dispose; pthread_mutex_init(&port_ticket->lock, NULL); pthread_mutex_init(&port_ticket->revoke_lock, NULL); + pthread_mutex_init(&port_ticket->port_rewiring_lock, NULL); pthread_cond_init(&port_ticket->issued, NULL); pthread_cond_init(&port_ticket->revoked, NULL); @@ -460,6 +492,7 @@ static int stream_rewire_audio(xine_post_out_t *output, void *data) if (!data) return 0; + stream->xine->port_ticket->lock_port_rewiring(stream->xine->port_ticket, -1); stream->xine->port_ticket->revoke(stream->xine->port_ticket, 1); if (stream->audio_out->status(stream->audio_out, stream, &bits, &rate, &mode)) { @@ -470,6 +503,7 @@ static int stream_rewire_audio(xine_post_out_t *output, void *data) stream->audio_out = new_port; stream->xine->port_ticket->issue(stream->xine->port_ticket, 1); + stream->xine->port_ticket->unlock_port_rewiring(stream->xine->port_ticket); return 1; } @@ -484,6 +518,7 @@ static int stream_rewire_video(xine_post_out_t *output, void *data) if (!data) return 0; + stream->xine->port_ticket->lock_port_rewiring(stream->xine->port_ticket, -1); stream->xine->port_ticket->revoke(stream->xine->port_ticket, 1); if (stream->video_out->status(stream->video_out, stream, &width, &height, &img_duration)) { @@ -494,6 +529,7 @@ static int stream_rewire_video(xine_post_out_t *output, void *data) stream->video_out = new_port; stream->xine->port_ticket->issue(stream->xine->port_ticket, 1); + stream->xine->port_ticket->unlock_port_rewiring(stream->xine->port_ticket); return 1; } @@ -2005,6 +2041,9 @@ const char *const *xine_get_log_names (xine_t *this) { static inline void check_log_alloc (xine_t *this, int buf) { + if ( this->log_buffers[buf] ) + return; + pthread_mutex_lock (&this->log_lock); if ( ! this->log_buffers[buf] ) @@ -2104,3 +2143,60 @@ int _x_query_buffer_usage(xine_stream_t *stream, int *num_video_buffers, int *nu return ticket_acquired != 0; } + +int _x_lock_port_rewiring(xine_t *xine, int ms_timeout) +{ + return xine->port_ticket->lock_port_rewiring(xine->port_ticket, ms_timeout); +} + +void _x_unlock_port_rewiring(xine_t *xine) +{ + xine->port_ticket->unlock_port_rewiring(xine->port_ticket); +} + +int _x_lock_frontend(xine_stream_t *stream, int ms_to_time_out) +{ + if (ms_to_time_out >= 0) { + struct timespec abstime; + + struct timeval now; + gettimeofday(&now, 0); + + abstime.tv_sec = now.tv_sec + ms_to_time_out / 1000; + abstime.tv_nsec = now.tv_usec * 1000 + (ms_to_time_out % 1000) * 1e6; + + if (abstime.tv_nsec > 1e9) { + abstime.tv_nsec -= 1e9; + abstime.tv_sec++; + } + + return (0 == pthread_mutex_timedlock(&stream->frontend_lock, &abstime)); + } + + pthread_mutex_lock(&stream->frontend_lock); + return 1; +} + +void _x_unlock_frontend(xine_stream_t *stream) +{ + pthread_mutex_unlock(&stream->frontend_lock); +} + +int _x_query_unprocessed_osd_events(xine_stream_t *stream) +{ + video_overlay_manager_t *ovl; + int redraw_needed; + + if (!stream->xine->port_ticket->acquire_nonblocking(stream->xine->port_ticket, 1)) + return -1; + + ovl = stream->video_out->get_overlay_manager(stream->video_out); + redraw_needed = ovl->redraw_needed(ovl, 0); + + if (redraw_needed) + stream->video_out->trigger_drawing(stream->video_out); + + stream->xine->port_ticket->release_nonblocking(stream->xine->port_ticket, 1); + + return redraw_needed; +} diff --git a/src/xine-engine/xine_internal.h b/src/xine-engine/xine_internal.h index dfce36cae..6db64eab8 100644 --- a/src/xine-engine/xine_internal.h +++ b/src/xine-engine/xine_internal.h @@ -170,6 +170,9 @@ struct xine_ticket_s { * be used in combination with acquire_nonblocking() */ void (*release_nonblocking)(xine_ticket_t *self, int irrevocable); + int (*lock_port_rewiring)(xine_ticket_t *self, int ms_timeout); + void (*unlock_port_rewiring)(xine_ticket_t *self); + void (*dispose)(xine_ticket_t *self); pthread_mutex_t lock; @@ -181,6 +184,7 @@ struct xine_ticket_s { int pending_revocations; int atomic_revoke; pthread_t atomic_revoker_thread; + pthread_mutex_t port_rewiring_lock; #endif }; @@ -370,6 +374,11 @@ struct xine_stream_s { */ int _x_query_buffer_usage(xine_stream_t *stream, int *num_video_buffers, int *num_audio_buffers, int *num_video_frames, int *num_audio_frames) XINE_PROTECTED; +int _x_lock_port_rewiring(xine_t *xine, int ms_to_time_out) XINE_PROTECTED; +void _x_unlock_port_rewiring(xine_t *xine) XINE_PROTECTED; +int _x_lock_frontend(xine_stream_t *stream, int ms_to_time_out) XINE_PROTECTED; +void _x_unlock_frontend(xine_stream_t *stream) XINE_PROTECTED; +int _x_query_unprocessed_osd_events(xine_stream_t *stream) XINE_PROTECTED; void _x_handle_stream_end (xine_stream_t *stream, int non_user) XINE_PROTECTED; |