summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarren Salt <linux@youmustbejoking.demon.co.uk>2007-05-06 14:54:30 +0100
committerDarren Salt <linux@youmustbejoking.demon.co.uk>2007-05-06 14:54:30 +0100
commit9f0ee3dfe65977d83447d5412793d2cdcece6c38 (patch)
tree72625d3223f32d48086c55ed360639fd2075c59b
parent87c856660802c454b300bc463e7cadf273ed0bbf (diff)
parent42db183b596601354643b6e8f4997109b2324f6d (diff)
downloadxine-lib-9f0ee3dfe65977d83447d5412793d2cdcece6c38.tar.gz
xine-lib-9f0ee3dfe65977d83447d5412793d2cdcece6c38.tar.bz2
Merge Reinhard Nissl's xxmc fixes and related changes.
-rw-r--r--src/video_out/video_out_xxmc.c108
-rw-r--r--src/xine-engine/xine.c77
-rw-r--r--src/xine-engine/xine_internal.h11
3 files changed, 165 insertions, 31 deletions
diff --git a/src/video_out/video_out_xxmc.c b/src/video_out/video_out_xxmc.c
index fd19f391b..11bfc7e1a 100644
--- a/src/video_out/video_out_xxmc.c
+++ b/src/video_out/video_out_xxmc.c
@@ -977,7 +977,7 @@ static void xvmc_check_colorkey_properties(xxmc_driver_t *driver)
static int xxmc_xvmc_update_context(xxmc_driver_t *driver, xxmc_frame_t *frame,
- uint32_t width, uint32_t height)
+ uint32_t width, uint32_t height, int frame_format_xxmc)
{
xine_xxmc_t *xxmc = &frame->xxmc_data;
@@ -991,8 +991,12 @@ static int xxmc_xvmc_update_context(xxmc_driver_t *driver, xxmc_frame_t *frame,
xprintf(driver->xine, XINE_VERBOSITY_LOG,
"video_out_xxmc: New format. Need to change XvMC Context.\n"
- "width: %d height: %d mpeg: %d acceleration: %d\n", width, height,
- xxmc->mpeg, xxmc->acceleration);
+ "width: %d height: %d", width, height);
+ if (frame_format_xxmc) {
+ xprintf(driver->xine, XINE_VERBOSITY_LOG,
+ " mpeg: %d acceleration: %d", xxmc->mpeg, xxmc->acceleration);
+ }
+ xprintf(driver->xine, XINE_VERBOSITY_LOG, "\n");
if (frame->xvmc_surf)
xxmc_xvmc_free_surface( driver , frame->xvmc_surf);
@@ -1000,7 +1004,7 @@ static int xxmc_xvmc_update_context(xxmc_driver_t *driver, xxmc_frame_t *frame,
xxmc_dispose_context( driver );
- if (xxmc_find_context( driver, xxmc, width, height )) {
+ if (frame_format_xxmc && xxmc_find_context( driver, xxmc, width, height )) {
xxmc_create_context( driver, width, height);
xvmc_check_colorkey_properties( driver );
xxmc_setup_subpictures(driver, width, height);
@@ -1231,7 +1235,7 @@ static void xxmc_do_update_frame(vo_driver_t *this_gen,
(this->xvmc_width != width) ||
(this->xvmc_height != height)) {
this->last_accel_request = xxmc->acceleration;
- xxmc_xvmc_update_context(this, frame, width, height);
+ xxmc_xvmc_update_context(this, frame, width, height, 1);
} else {
this->last_accel_request = xxmc->acceleration;
}
@@ -1254,6 +1258,11 @@ static void xxmc_do_update_frame(vo_driver_t *this_gen,
xvmc_context_writer_unlock( &this->xvmc_lock);
} else {
+ /* switch back to an unaccelerated context */
+ if (this->last_accel_request != 0xFFFFFFFF) {
+ this->last_accel_request = 0xFFFFFFFF;
+ xxmc_xvmc_update_context(this, frame, width, height, 0);
+ }
frame->vo_frame.proc_duplicate_frame_data = NULL;
xxmc_do_update_frame_xv(this_gen, frame_gen, width, height, ratio,
format, flags);
@@ -1579,6 +1588,28 @@ static void xxmc_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen)
xxmc_frame_t *frame = (xxmc_frame_t *) frame_gen;
xine_xxmc_t *xxmc = &frame->xxmc_data;
int first_field;
+ int disable_deinterlace = 0;
+ struct timeval tv_top;
+
+ /*
+ * take time to calculate the time to sleep for the bottom field
+ */
+ gettimeofday(&tv_top, 0);
+
+ /*
+ * bob deinterlacing doesn't make much sense for still images or at replay speeds
+ * other than 100 %, so let's disable deinterlacing at all for this frame
+ */
+ if (this->deinterlace_enabled && this->bob) {
+ disable_deinterlace = frame->vo_frame.progressive_frame
+ || !frame->vo_frame.stream
+ || xine_get_param(frame->vo_frame.stream, XINE_PARAM_FINE_SPEED) != XINE_FINE_SPEED_NORMAL;
+ if (!disable_deinterlace) {
+ int vo_bufs_in_fifo = 0;
+ _x_query_buffer_usage(frame->vo_frame.stream, NULL, NULL, &vo_bufs_in_fifo, NULL);
+ disable_deinterlace = (vo_bufs_in_fifo <= 0);
+ }
+ }
/*
* queue frames (deinterlacing)
@@ -1589,6 +1620,20 @@ static void xxmc_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen)
xxmc_add_recent_frame (this, frame); /* deinterlacing */
+ /*
+ * the current implementation doesn't need recent frames for deinterlacing,
+ * but as most of the time we only have a little number of frames available
+ * per device, we only hold references to the most recent frame by filling
+ * the whole buffer with the same frame
+ */
+ {
+ int i;
+ for (i = 1; i < VO_NUM_RECENT_FRAMES; i++) {
+ frame->vo_frame.lock(&frame->vo_frame);
+ xxmc_add_recent_frame (this, frame); /* deinterlacing */
+ }
+ }
+
if ((frame->format == XINE_IMGFMT_XXMC) &&
(!xxmc->decoded || !xxmc_xvmc_surface_valid(this, frame->xvmc_surf))) {
xvmc_context_reader_unlock( &this->xvmc_lock );
@@ -1616,7 +1661,7 @@ static void xxmc_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen)
first_field = (frame->vo_frame.top_field_first) ? XVMC_TOP_FIELD : XVMC_BOTTOM_FIELD;
first_field = (this->bob) ? first_field : XVMC_TOP_FIELD;
- this->cur_field = (this->deinterlace_enabled) ? first_field : XVMC_FRAME_PICTURE;
+ this->cur_field = (this->deinterlace_enabled && !disable_deinterlace) ? first_field : XVMC_FRAME_PICTURE;
xxmc_redraw_needed (this_gen);
if (frame->format == XINE_IMGFMT_XXMC) {
@@ -1629,21 +1674,42 @@ static void xxmc_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen)
this->sc.output_width, this->sc.output_height,
this->cur_field);
XVMCUNLOCKDISPLAY( this->display );
- if (this->deinterlace_enabled && this->bob) {
- unsigned
- ms_per_field = 500 * frame->vo_frame.duration / 90000 - 2;
-
- usleep(ms_per_field*1000);
- this->cur_field = (frame->vo_frame.top_field_first) ? XVMC_BOTTOM_FIELD : XVMC_TOP_FIELD;
+ if (this->deinterlace_enabled && !disable_deinterlace && this->bob) {
+ struct timeval tv_middle;
+ long us_spent_so_far, us_per_field = frame->vo_frame.duration * 50 / 9;
- XVMCLOCKDISPLAY( this->display );
- XvMCPutSurface( this->display, frame->xvmc_surf , this->drawable,
- this->sc.displayed_xoffset, this->sc.displayed_yoffset,
- this->sc.displayed_width, this->sc.displayed_height,
- this->sc.output_xoffset, this->sc.output_yoffset,
- this->sc.output_width, this->sc.output_height,
- this->cur_field);
- XVMCUNLOCKDISPLAY( this->display );
+ gettimeofday(&tv_middle, 0);
+ us_spent_so_far = (tv_middle.tv_sec - tv_top.tv_sec) * 1000000 + (tv_middle.tv_usec - tv_top.tv_usec);
+ if (us_spent_so_far < 0)
+ us_spent_so_far = 0;
+
+ /*
+ * typically, the operations above take just a few milliseconds, but when the
+ * driver actively waits to sync on the next field, we better skip showing the
+ * other field as it would lead to further busy waiting
+ * so display the other field only if we've spent less than 75 % of the per
+ * field time so far
+ */
+ if (4 * us_spent_so_far < 3 * us_per_field) {
+ long us_delay = (us_per_field - 2000) - us_spent_so_far;
+ if (us_delay > 0) {
+ xvmc_context_reader_unlock( &this->xvmc_lock );
+ xine_usec_sleep(us_delay);
+ LOCK_AND_SURFACE_VALID( this, frame->xvmc_surf );
+ }
+
+ this->cur_field = (frame->vo_frame.top_field_first) ? XVMC_BOTTOM_FIELD : XVMC_TOP_FIELD;
+
+ XVMCLOCKDISPLAY( this->display );
+ XvMCPutSurface( this->display, frame->xvmc_surf , this->drawable,
+ this->sc.displayed_xoffset, this->sc.displayed_yoffset,
+ this->sc.displayed_width, this->sc.displayed_height,
+ this->sc.output_xoffset, this->sc.output_yoffset,
+ this->sc.output_width, this->sc.output_height,
+ this->cur_field);
+
+ XVMCUNLOCKDISPLAY( this->display );
+ }
}
} else {
XLockDisplay (this->display);
@@ -1934,7 +2000,7 @@ static void xxmc_dispose (vo_driver_t *this_gen) {
for( i=0; i < VO_NUM_RECENT_FRAMES; i++ ) {
if( this->recent_frames[i] )
- this->recent_frames[i]->vo_frame.dispose
+ this->recent_frames[i]->vo_frame.free
(&this->recent_frames[i]->vo_frame);
this->recent_frames[i] = NULL;
}
diff --git a/src/xine-engine/xine.c b/src/xine-engine/xine.c
index f49a988c9..9623668dc 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);
@@ -227,12 +254,14 @@ 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->dispose = ticket_dispose;
pthread_mutex_init(&port_ticket->lock, NULL);
pthread_mutex_init(&port_ticket->revoke_lock, NULL);
@@ -2040,3 +2069,31 @@ 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;
+}
diff --git a/src/xine-engine/xine_internal.h b/src/xine-engine/xine_internal.h
index 30899a4b3..c88bcc904 100644
--- a/src/xine-engine/xine_internal.h
+++ b/src/xine-engine/xine_internal.h
@@ -159,6 +159,15 @@ 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);
+
void (*dispose)(xine_ticket_t *self);
pthread_mutex_t lock;
@@ -357,6 +366,8 @@ 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;
+
void _x_handle_stream_end (xine_stream_t *stream, int non_user) XINE_PROTECTED;
/* report message to UI. usually these are async errors */