diff options
author | Reinhard Nißl <rnissl@gmx.de> | 2007-04-12 23:36:51 +0200 |
---|---|---|
committer | Reinhard Nißl <rnissl@gmx.de> | 2007-04-12 23:36:51 +0200 |
commit | 7b50cbef25c8e2769bfbdd801b7318bb86047f87 (patch) | |
tree | 802fb4da1378365b7c9a00681136b3731a65d087 /src | |
parent | e8aa9780585fcec85b2a019af6e248687189e97c (diff) | |
download | xine-lib-7b50cbef25c8e2769bfbdd801b7318bb86047f87.tar.gz xine-lib-7b50cbef25c8e2769bfbdd801b7318bb86047f87.tar.bz2 |
Make bob deinterlacing more precisely and skip it on demand.
Bob deinterlacing is implemented as showing the top field, sleeping
for half the frame duration and showing the bottom field. Most
drivers tend to synchronize displaying a field on the VBI and thus
displaying a field may take up to half the frame duration in certain
cases.
According to the original code, the sleep took always half the
frame duration and therefore the second field could get displayed
too late. As a result, the driver was syncing to VBI most often,
so that things got even worse.
The changed code now calculates the sleep time in a way that the
second field gets displayed half the frame duration after the
first field. Moreover, it monitors how much time was spent to
display the first field and when this time exceeds 75 % of the
field time (= half the frame time), it skips displaying the second
field, as usually this is an indicator that the driver has no
more frame buffers left. So displaying the second field would just
make things go worse.
Diffstat (limited to 'src')
-rw-r--r-- | src/video_out/video_out_xxmc.c | 53 |
1 files changed, 40 insertions, 13 deletions
diff --git a/src/video_out/video_out_xxmc.c b/src/video_out/video_out_xxmc.c index 53e4b7995..37dad7a99 100644 --- a/src/video_out/video_out_xxmc.c +++ b/src/video_out/video_out_xxmc.c @@ -1588,6 +1588,12 @@ 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; + struct timeval tv_top; + + /* + * take time to calculate the time to sleep for the bottom field + */ + gettimeofday(&tv_top, 0); /* * queue frames (deinterlacing) @@ -1653,20 +1659,41 @@ static void xxmc_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) 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; + 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); |