summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/xine-engine/post.c13
-rw-r--r--src/xine-engine/video_out.c49
-rw-r--r--src/xine-engine/video_out.h3
-rw-r--r--src/xine-engine/xine.c170
-rw-r--r--src/xine-engine/xine_internal.h20
5 files changed, 243 insertions, 12 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_out.c b/src/xine-engine/video_out.c
index 2a3ee1980..d61df1eb2 100644
--- a/src/xine-engine/video_out.c
+++ b/src/xine-engine/video_out.c
@@ -1043,6 +1043,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 +1114,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 +1244,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 +1630,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 +1702,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 +1806,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;
@@ -1842,6 +1884,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 7b42c43ed..06e5eaaa9 100644
--- a/src/xine-engine/video_out.h
+++ b/src/xine-engine/video_out.h
@@ -205,6 +205,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/xine.c b/src/xine-engine/xine.c
index f49a988c9..840c91f3f 100644
--- a/src/xine-engine/xine.c
+++ b/src/xine-engine/xine.c
@@ -127,23 +127,42 @@ void _x_extra_info_merge( extra_info_t *dst, extra_info_t *src ) {
}
}
-static void ticket_acquire(xine_ticket_t *this, int irrevocable) {
+static int ticket_acquire_internal(xine_ticket_t *this, int irrevocable, int nonblocking) {
+ int must_wait = 0;
pthread_mutex_lock(&this->lock);
if (this->ticket_revoked && !this->irrevocable_tickets)
- pthread_cond_wait(&this->issued, &this->lock);
+ must_wait = !nonblocking;
else if (this->atomic_revoke && !pthread_equal(this->atomic_revoker_thread, pthread_self()))
+ must_wait = 1;
+
+ if (must_wait) {
+ if (nonblocking) {
+ pthread_mutex_unlock(&this->lock);
+ return 0;
+ }
+
pthread_cond_wait(&this->issued, &this->lock);
+ }
this->tickets_granted++;
if (irrevocable)
this->irrevocable_tickets++;
pthread_mutex_unlock(&this->lock);
+ return 1;
}
-static void ticket_release(xine_ticket_t *this, int irrevocable) {
+static int ticket_acquire_nonblocking(xine_ticket_t *this, int irrevocable) {
+ return ticket_acquire_internal(this, irrevocable, 1);
+}
+
+static void ticket_acquire(xine_ticket_t *this, int irrevocable) {
+ ticket_acquire_internal(this, irrevocable, 0);
+}
+
+static void ticket_release_internal(xine_ticket_t *this, int irrevocable, int nonblocking) {
pthread_mutex_lock(&this->lock);
@@ -153,12 +172,20 @@ static void ticket_release(xine_ticket_t *this, int irrevocable) {
if (this->ticket_revoked && !this->tickets_granted)
pthread_cond_broadcast(&this->revoked);
- if (this->ticket_revoked && !this->irrevocable_tickets)
+ if (this->ticket_revoked && !this->irrevocable_tickets && !nonblocking)
pthread_cond_wait(&this->issued, &this->lock);
pthread_mutex_unlock(&this->lock);
}
+static void ticket_release_nonblocking(xine_ticket_t *this, int irrevocable) {
+ ticket_release_internal(this, irrevocable, 1);
+}
+
+static void ticket_release(xine_ticket_t *this, int irrevocable) {
+ ticket_release_internal(this, irrevocable, 0);
+}
+
static void ticket_renew(xine_ticket_t *this, int irrevocable) {
pthread_mutex_lock(&this->lock);
@@ -212,8 +239,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);
@@ -227,15 +283,20 @@ static xine_ticket_t *ticket_init(void) {
port_ticket = (xine_ticket_t *) xine_xmalloc(sizeof(xine_ticket_t));
- port_ticket->acquire = ticket_acquire;
- port_ticket->release = ticket_release;
- port_ticket->renew = ticket_renew;
- port_ticket->issue = ticket_issue;
- port_ticket->revoke = ticket_revoke;
- port_ticket->dispose = ticket_dispose;
+ port_ticket->acquire_nonblocking = ticket_acquire_nonblocking;
+ port_ticket->acquire = ticket_acquire;
+ port_ticket->release_nonblocking = ticket_release_nonblocking;
+ port_ticket->release = ticket_release;
+ 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);
@@ -429,6 +490,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)) {
@@ -439,6 +501,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;
}
@@ -453,6 +516,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)) {
@@ -463,6 +527,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;
}
@@ -2040,3 +2105,88 @@ int xine_stream_master_slave(xine_stream_t *master, xine_stream_t *slave,
slave->master = master->master;
return 1;
}
+
+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)
+{
+ int ticket_acquired = -1;
+
+ if (num_video_buffers)
+ *num_video_buffers = (stream->video_fifo ? stream->video_fifo->size(stream->video_fifo) : 0);
+
+ if (num_audio_buffers)
+ *num_audio_buffers = (stream->audio_fifo ? stream->audio_fifo->size(stream->audio_fifo) : 0);
+
+ if ((num_video_frames && stream->video_out)
+ || (num_audio_frames && stream->audio_out)) {
+
+ ticket_acquired = stream->xine->port_ticket->acquire_nonblocking(stream->xine->port_ticket, 1);
+ }
+
+ if (num_video_frames)
+ *num_video_frames = ((ticket_acquired && stream->video_out) ? stream->video_out->get_property(stream->video_out, VO_PROP_BUFS_IN_FIFO) : 0);
+
+ if (num_audio_frames)
+ *num_audio_frames = ((ticket_acquired && stream->audio_out) ? stream->audio_out->get_property(stream->audio_out, AO_PROP_BUFS_IN_FIFO) : 0);
+
+ if (ticket_acquired > 0)
+ stream->xine->port_ticket->release_nonblocking(stream->xine->port_ticket, 1);
+
+ 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 30899a4b3..f4041452d 100644
--- a/src/xine-engine/xine_internal.h
+++ b/src/xine-engine/xine_internal.h
@@ -159,6 +159,18 @@ struct xine_ticket_s {
* revocation or by other threads acquiring tickets */
void (*revoke)(xine_ticket_t *self, int atomic);
+ /* behaves like acquire() but doesn't block the calling thread; when
+ * the thread would have been blocked, 0 is returned otherwise 1
+ * this function acquires a ticket even if ticket revocation is active */
+ int (*acquire_nonblocking)(xine_ticket_t *self, int irrevocable);
+
+ /* behaves like release() but doesn't block the calling thread; should
+ * 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;
@@ -170,6 +182,7 @@ struct xine_ticket_s {
int pending_revocations;
int atomic_revoke;
pthread_t atomic_revoker_thread;
+ pthread_mutex_t port_rewiring_lock;
#endif
};
@@ -357,6 +370,13 @@ struct xine_stream_s {
* private function prototypes:
*/
+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;
/* report message to UI. usually these are async errors */