diff options
Diffstat (limited to 'src/video_out/video_out_xxmc.c')
-rw-r--r-- | src/video_out/video_out_xxmc.c | 419 |
1 files changed, 278 insertions, 141 deletions
diff --git a/src/video_out/video_out_xxmc.c b/src/video_out/video_out_xxmc.c index 0abe2f0fc..98ce99f1f 100644 --- a/src/video_out/video_out_xxmc.c +++ b/src/video_out/video_out_xxmc.c @@ -16,9 +16,7 @@ * * You should have received a copy of the GNU General Public License * 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_xxmc.c,v 1.23 2007/03/25 23:13:53 dgp85 Exp $ + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA * * video_out_xxmc.c, X11 decoding accelerated video extension interface for xine * @@ -31,9 +29,8 @@ * * overlay support by James Courtier-Dutton <James@superbug.demon.co.uk> - July 2001 * X11 unscaled overlay support by Miguel Freitas - Nov 2003 - * XvMC VLD implementation by Thomas Hellström - 2004, 2005. - * XvMC merge by Thomas Hellström - Sep 2004 - * + * XvMC VLD implementation by Thomas Hellström - 2004, 2005. + * XvMC merge by Thomas Hellström - Sep 2004 */ @@ -54,7 +51,7 @@ static void dispose_ximage (xxmc_driver_t *this, XShmSegmentInfo *shminfo, * is more efficient than VLD. */ -static unsigned accel_priority[] = { +static const unsigned int accel_priority[] = { #ifdef HAVE_VLDXVMC XINE_XVMC_ACCEL_VLD, #endif @@ -165,14 +162,10 @@ static void xxmc_xvmc_surface_handler_construct(xxmc_driver_t *this) xvmc_surface_handler_t *handler = &this->xvmc_surf_handler; pthread_mutex_init(&handler->mutex,NULL); - for (i=0; i<XVMC_MAX_SURFACES; ++i) { - handler->surfInUse[i] = 0; - handler->surfValid[i] = 0; - } - for (i=0; i<XVMC_MAX_SUBPICTURES; ++i) { - handler->subInUse[i] = 0; - handler->subValid[i] = 0; - } + memset(handler->surfInUse, 0, sizeof(*handler->surfInUse)*XVMC_MAX_SURFACES); + memset(handler->surfValid, 0, sizeof(*handler->surfValid)*XVMC_MAX_SURFACES); + memset(handler->subInUse, 0, sizeof(*handler->subInUse)*XVMC_MAX_SUBPICTURES); + memset(handler->subValid, 0, sizeof(*handler->subValid)*XVMC_MAX_SUBPICTURES); } static void xxmc_xvmc_destroy_surfaces(xxmc_driver_t *this) @@ -242,7 +235,7 @@ static XvMCSurface *xxmc_xvmc_alloc_surface(xxmc_driver_t *this, } XVMCUNLOCKDISPLAY( this->display ); xprintf (this->xine, XINE_VERBOSITY_DEBUG, - "video_out_xxmc: Created surface %d\n",i); + LOG_MODULE ": Created surface %d\n",i); handler->surfInUse[i] = 1; handler->surfValid[i] = 1; pthread_mutex_unlock(&handler->mutex); @@ -262,7 +255,7 @@ static void xxmc_xvmc_free_surface(xxmc_driver_t *this, XvMCSurface *surf) if (index >= XVMC_MAX_SURFACES) return; pthread_mutex_lock(&handler->mutex); xprintf (this->xine, XINE_VERBOSITY_DEBUG, - "video_out_xxmc: Disposing of surface %d\n",index); + LOG_MODULE ": Disposing of surface %d\n",index); handler->surfInUse[index]--; xxmc_xvmc_dump_surfaces(this); pthread_mutex_unlock(&handler->mutex); @@ -322,7 +315,7 @@ static XvMCSubpicture *xxmc_xvmc_alloc_subpicture } XVMCUNLOCKDISPLAY( this->display ); xprintf (this->xine, XINE_VERBOSITY_DEBUG, - "video_out_xxmc: Created subpicture %d\n",i); + LOG_MODULE ": Created subpicture %d\n",i); handler->subInUse[i] = 1; handler->subValid[i] = 1; pthread_mutex_unlock(&handler->mutex); @@ -343,7 +336,7 @@ static void xxmc_xvmc_free_subpicture(xxmc_driver_t *this, XvMCSubpicture *sub) if (index >= XVMC_MAX_SUBPICTURES) return; pthread_mutex_lock(&handler->mutex); xprintf (this->xine, XINE_VERBOSITY_DEBUG, - "video_out_xxmc: Disposing of subpicture %d\n",index); + LOG_MODULE ": Disposing of subpicture %d\n",index); handler->subInUse[index] = 0; xxmc_xvmc_dump_subpictures(this); pthread_mutex_unlock(&handler->mutex); @@ -371,15 +364,15 @@ static int xxmc_lock_and_validate_surfaces(vo_frame_t *cur_frame, switch(pc_type) { case XINE_PICT_B_TYPE: - frame = (xxmc_frame_t *) bw_frame; + frame = XXMC_FRAME(bw_frame); if (!xxmc_xvmc_surface_valid( driver, frame->xvmc_surf)) break; /* fall through */ case XINE_PICT_P_TYPE: - frame = (xxmc_frame_t *) fw_frame; + frame = XXMC_FRAME(fw_frame); if (!xxmc_xvmc_surface_valid( driver, frame->xvmc_surf)) break; /* fall through */ default: - frame = (xxmc_frame_t *) cur_frame; + frame = XXMC_FRAME(cur_frame); if (!xxmc_xvmc_surface_valid( driver, frame->xvmc_surf)) break; return 0; } @@ -410,7 +403,7 @@ static void xvmc_flush(vo_frame_t *this_gen) { xxmc_frame_t - *frame = (xxmc_frame_t *) this_gen; + *frame = XXMC_FRAME(this_gen); xxmc_driver_t *driver = (xxmc_driver_t *) this_gen->driver; @@ -458,6 +451,7 @@ static void xxmc_duplicate_frame_data(vo_frame_t *this_gen, return; } this->xxmc_data = *xxmc; + this->xxmc_data.xvmc.vo_frame = &this->vo_frame; this->width = original->width; this->height = original->height; this->format = original->format; @@ -572,6 +566,7 @@ static vo_frame_t *xxmc_alloc_frame (vo_driver_t *this_gen) { frame->vo_frame.driver = this_gen; frame->last_sw_format = 0; frame->vo_frame.accel_data = &frame->xxmc_data; + frame->xxmc_data.xvmc.vo_frame = &frame->vo_frame; frame->image = NULL; xprintf (this->xine, XINE_VERBOSITY_DEBUG, "Allocating frame\n"); @@ -608,11 +603,6 @@ static XvImage *create_ximage (xxmc_driver_t *this, XShmSegmentInfo *shminfo, unsigned int xv_format; XvImage *image = NULL; - if (width <= 0) - width = 1; - if (height <= 0) - height = 1; - if (this->use_pitch_alignment) { width = (width + 7) & ~0x7; } @@ -647,8 +637,9 @@ static XvImage *create_ximage (xxmc_driver_t *this, XShmSegmentInfo *shminfo, if (image == NULL ) { xprintf(this->xine, XINE_VERBOSITY_LOG, - _("video_out_xxmc: XvShmCreateImage failed\n" - "video_out_xxmc: => not using MIT Shared Memory extension.\n")); + _("%s: XvShmCreateImage failed\n"), LOG_MODULE); + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("%s: => not using MIT Shared Memory extension.\n"), LOG_MODULE); this->use_shm = 0; goto finishShmTesting; } @@ -657,16 +648,18 @@ static XvImage *create_ximage (xxmc_driver_t *this, XShmSegmentInfo *shminfo, if (image->data_size==0) { xprintf(this->xine, XINE_VERBOSITY_LOG, - _("video_out_xxmc: XvShmCreateImage returned a zero size\n" - "video_out_xxmc: => not using MIT Shared Memory extension.\n")); + _("%s: XvShmCreateImage returned a zero size\n"), LOG_MODULE); + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("%s: => not using MIT Shared Memory extension.\n"), LOG_MODULE); this->use_shm = 0; goto finishShmTesting; } if (shminfo->shmid < 0 ) { xprintf(this->xine, XINE_VERBOSITY_LOG, - _("video_out_xxmc: shared memory error in shmget: %s\n" - "video_out_xxmc: => not using MIT Shared Memory extension.\n"), strerror(errno)); + _("%s: shared memory error in shmget: %s\n"), LOG_MODULE, strerror(errno)); + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("%s: => not using MIT Shared Memory extension.\n"), LOG_MODULE); this->use_shm = 0; goto finishShmTesting; } @@ -675,14 +668,14 @@ static XvImage *create_ximage (xxmc_driver_t *this, XShmSegmentInfo *shminfo, if (shminfo->shmaddr == NULL) { xprintf(this->xine, XINE_VERBOSITY_DEBUG, - "video_out_xxmc: shared memory error (address error NULL)\n"); + LOG_MODULE ": shared memory error (address error NULL)\n"); this->use_shm = 0; goto finishShmTesting; } if (shminfo->shmaddr == ((char *) -1)) { xprintf(this->xine, XINE_VERBOSITY_DEBUG, - "video_out_xxmc: shared memory error (address error)\n"); + LOG_MODULE ": shared memory error (address error)\n"); this->use_shm = 0; goto finishShmTesting; } @@ -696,12 +689,13 @@ static XvImage *create_ximage (xxmc_driver_t *this, XShmSegmentInfo *shminfo, shmctl(shminfo->shmid, IPC_RMID, 0); if (gX11Fail) { - xprintf(this->xine, XINE_VERBOSITY_LOG, - _("video_out_xxmc: x11 error during shared memory XImage creation\n" - "video_out_xxmc: => not using MIT Shared Memory extension.\n")); shmdt (shminfo->shmaddr); shmctl (shminfo->shmid, IPC_RMID, 0); shminfo->shmid = -1; + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("%s: x11 error during shared memory XImage creation\n"), LOG_MODULE); + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("%s: => not using MIT Shared Memory extension.\n"), LOG_MODULE); this->use_shm = 0; goto finishShmTesting; } @@ -766,13 +760,13 @@ static void xxmc_dispose_context(xxmc_driver_t *driver) } xprintf(driver->xine, XINE_VERBOSITY_LOG, - "video_out_xxmc: Freeing up XvMC Surfaces and subpictures.\n"); + LOG_MODULE ": Freeing up XvMC Surfaces and subpictures.\n"); if (driver->xvmc_palette) free(driver->xvmc_palette); _x_dispose_xx44_palette( &driver->palette ); xxmc_xvmc_destroy_subpictures( driver ); xxmc_xvmc_destroy_surfaces( driver ); xprintf(driver->xine, XINE_VERBOSITY_LOG, - "video_out_xxmc: Freeing up XvMC Context.\n"); + LOG_MODULE ": Freeing up XvMC Context.\n"); XLockDisplay (driver->display); if (driver->subImage) dispose_ximage(driver, &driver->subShmInfo, driver->subImage); @@ -812,10 +806,10 @@ static int xxmc_find_context(xxmc_driver_t *driver, xine_xxmc_t *xxmc, curCap = driver->xvmc_cap; for (i =0; i < driver->xvmc_num_cap; ++i) { xprintf(driver->xine, XINE_VERBOSITY_LOG, - "video_out_xxmc: Surface type %d. Capabilities 0x%8x 0x%8x\n",i, + LOG_MODULE ": Surface type %d. Capabilities 0x%8x 0x%8x\n",i, curCap->mpeg_flags,curCap->accel_flags); xprintf(driver->xine, XINE_VERBOSITY_LOG, - "video_out_xxmc: Requests: 0x%8x 0x%8x\n", + LOG_MODULE ": Requests: 0x%8x 0x%8x\n", request_mpeg_flags,request_accel_flags); if (((curCap->mpeg_flags & request_mpeg_flags) == request_mpeg_flags) && ((curCap->accel_flags & request_accel_flags)) && @@ -846,7 +840,7 @@ static int xxmc_create_context(xxmc_driver_t *driver, unsigned width, unsigned h curCap = driver->xvmc_cap + driver->xvmc_cur_cap; xprintf(driver->xine, XINE_VERBOSITY_LOG, - "video_out_xxmc: Creating new XvMC Context %d\n",curCap->type_id); + LOG_MODULE ": Creating new XvMC Context %d\n",curCap->type_id); XVMCLOCKDISPLAY( driver->display ); if (Success == XvMCCreateContext( driver->display, driver->xv_port, curCap->type_id, width, @@ -879,7 +873,7 @@ static void xxmc_setup_subpictures(xxmc_driver_t *driver, unsigned width, unsign if ((driver->xvmc_backend_subpic = (curCap->flags & XVMC_BACKEND_SUBPICTURE))) xprintf(driver->xine, XINE_VERBOSITY_LOG, - "video_out_xxmc: Using Backend subpictures.\n"); + LOG_MODULE ": Using Backend subpictures.\n"); if (!driver->subImage) { /* @@ -895,7 +889,7 @@ static void xxmc_setup_subpictures(xxmc_driver_t *driver, unsigned width, unsign XUnlockDisplay (driver->display); if (NULL == driver->subImage) { xprintf(driver->xine, XINE_VERBOSITY_LOG, - "video_out_xxmc: Failed allocating XvImage for supbictures.\n"); + LOG_MODULE ": Failed allocating XvImage for supbictures.\n"); return; } } @@ -977,7 +971,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; @@ -990,9 +984,13 @@ static int xxmc_xvmc_update_context(xxmc_driver_t *driver, xxmc_frame_t *frame, return 0; 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); + LOG_MODULE ": New format. Need to change XvMC Context.\n" + LOG_MODULE ": 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,24 +998,24 @@ 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); if ((driver->xvmc_accel & (XINE_XVMC_ACCEL_MOCOMP | XINE_XVMC_ACCEL_IDCT))) { if (!xxmc_mocomp_create_macroblocks(driver, frame, 1)) { - lprintf("video_out_xxmc: ERROR: Macroblock allocation failed\n"); + printf(LOG_MODULE ": ERROR: Macroblock allocation failed\n"); xxmc_dispose_context( driver ); } } } if (!driver->contextActive) { - printf("video_out_xxmc: Using software decoding for this stream.\n"); + printf(LOG_MODULE ": Using software decoding for this stream.\n"); driver->xvmc_accel = 0; } else { - printf("video_out_xxmc: Using hardware decoding for this stream.\n"); + printf(LOG_MODULE ": Using hardware decoding for this stream.\n"); } driver->xvmc_mpeg = xxmc->mpeg; @@ -1053,9 +1051,9 @@ static void xxmc_frame_updates(xxmc_driver_t *driver, if (frame->xvmc_surf == NULL) { if (NULL == (frame->xvmc_surf = xxmc_xvmc_alloc_surface( driver, &driver->context))) { - fprintf(stderr, "video_out_xxmc: ERROR: Accelerated surface allocation failed.\n" - "video_out_xxmc: You are probably out of framebuffer memory.\n" - "video_out_xxmc: Falling back to software decoding.\n"); + fprintf(stderr, LOG_MODULE ": ERROR: Accelerated surface allocation failed.\n" + LOG_MODULE ": You are probably out of framebuffer memory.\n" + LOG_MODULE ": Falling back to software decoding.\n"); driver->xvmc_accel = 0; xxmc_dispose_context( driver ); return; @@ -1220,10 +1218,17 @@ static void xxmc_do_update_frame(vo_driver_t *this_gen, double ratio, int format, int flags) { xxmc_driver_t *this = (xxmc_driver_t *) this_gen; - xxmc_frame_t *frame = (xxmc_frame_t *) frame_gen; + xxmc_frame_t *frame = XXMC_FRAME(frame_gen); if ( XINE_IMGFMT_XXMC == format ) { xine_xxmc_t *xxmc = &frame->xxmc_data; + vo_frame_t orig_frame_content; + + if (frame_gen != &frame->vo_frame) { + /* this is an intercepted frame, so we need to detect and propagate any + * changes on the original vo_frame to all the intercepted frames */ + xine_fast_memcpy(&orig_frame_content, &frame->vo_frame, sizeof (vo_frame_t)); + } xvmc_context_writer_lock( &this->xvmc_lock); if (xxmc_accel_update(this, this->last_accel_request, xxmc->acceleration) || @@ -1231,7 +1236,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; } @@ -1239,7 +1244,7 @@ static void xxmc_do_update_frame(vo_driver_t *this_gen, if (this->contextActive) xxmc_frame_updates(this, frame, 1); - xxmc_do_update_frame_xv(this_gen, frame_gen, width, height, ratio, + xxmc_do_update_frame_xv(this_gen, &frame->vo_frame, width, height, ratio, xxmc->fallback_format, flags); if (!this->contextActive) { @@ -1253,9 +1258,41 @@ static void xxmc_do_update_frame(vo_driver_t *this_gen, xvmc_context_writer_unlock( &this->xvmc_lock); + if (frame_gen != &frame->vo_frame) { + /* this is an intercepted frame, so we need to detect and propagate any + * changes on the original vo_frame to all the intercepted frames */ + unsigned char *p0 = (unsigned char *)&orig_frame_content; + unsigned char *p1 = (unsigned char *)&frame->vo_frame; + int i; + for (i = 0; i < sizeof (vo_frame_t); i++) { + if (*p0 != *p1) { + /* propagate the change */ + vo_frame_t *f = frame_gen; + while (f->next) { + /* serveral restrictions apply when intercepting XXMC frames. So let's check + * the intercepted frames before modifing them and fail otherwise. */ + unsigned char *p = (unsigned char *)f + i; + if (*p != *p0) { + xprintf(this->xine, XINE_VERBOSITY_DEBUG, "xxmc_do_update_frame: a post plugin violates the restrictions on intercepting XXMC frames\n"); + _x_abort(); + } + + *p = *p1; + f = f->next; + } + } + p0++; + p1++; + } + } } 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, + xxmc_do_update_frame_xv(this_gen, &frame->vo_frame, width, height, ratio, format, flags); } } @@ -1482,6 +1519,7 @@ static void xxmc_overlay_blend (vo_driver_t *this_gen, vo_frame_t *frame_gen, xxmc_frame_t *frame = (xxmc_frame_t *) frame_gen; if (overlay->rle) { + this->scaled_osd_active = !overlay->unscaled; if( overlay->unscaled ) { if( this->ovl_changed && this->xoverlay ) { XLockDisplay (this->display); @@ -1491,6 +1529,7 @@ static void xxmc_overlay_blend (vo_driver_t *this_gen, vo_frame_t *frame_gen, } else if (frame->format == XINE_IMGFMT_XXMC) { if (this->ovl_changed && this->hwSubpictures) { if (this->new_subpic) { + int x0, y0, x1, y1, w, h; LOCK_AND_SURFACE_VALID( this, frame->xvmc_surf ); if (this->first_overlay) { memset(this->subImage->data,0,this->subImage->width* @@ -1501,13 +1540,29 @@ static void xxmc_overlay_blend (vo_driver_t *this_gen, vo_frame_t *frame_gen, this->subImage->height, this->subImage->width, &this->alphablend_extra_data, &this->palette, (this->subImage->id == FOURCC_IA44)); - XVMCLOCKDISPLAY( this->display ); - XvMCCompositeSubpicture( this->display, this->new_subpic, - this->subImage, - overlay->x, overlay->y,overlay->width, - overlay->height, - overlay->x, overlay->y); - XVMCUNLOCKDISPLAY( this->display ); + + /* clip overlay against sub image like in _x_blend_xx44() */ + x0 = overlay->x; + y0 = overlay->y; + x1 = x0 + overlay->width; + y1 = y0 + overlay->height; + w = this->subImage->width; + h = this->subImage->height; + + x0 = (x0 < 0) ? 0 : ((x0 > w) ? w : x0); + y0 = (y0 < 0) ? 0 : ((y0 > h) ? h : y0); + x1 = (x1 < 0) ? 0 : ((x1 > w) ? w : x1); + y1 = (y1 < 0) ? 0 : ((y1 > h) ? h : y1); + + /* anything left after clipping? */ + if (x0 != x1 && y0 != y1) { + XVMCLOCKDISPLAY( this->display ); + XvMCCompositeSubpicture( this->display, this->new_subpic, + this->subImage, + x0, y0, x1 - x0, y1 - y0, + x0, y0); + XVMCUNLOCKDISPLAY( this->display ); + } xvmc_context_reader_unlock( &this->xvmc_lock ); } } @@ -1579,6 +1634,35 @@ 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 = this->disable_bob_for_progressive_frames && frame->vo_frame.progressive_frame + || this->disable_bob_for_scaled_osd && this->scaled_osd_active + || !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); + } + } + + /* + * reset this flag now -- it will be set again before the next call to + * xxmc_display_frame() as long as there is a scaled OSD active on screen. + */ + this->scaled_osd_active = 0; /* * queue frames (deinterlacing) @@ -1587,6 +1671,15 @@ static void xxmc_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) xvmc_context_reader_lock( &this->xvmc_lock ); + /* + * the current implementation doesn't need recent frames for deinterlacing, + * but we need to hold references on the frame we are about to show and to + * the previous frame which is currently shown on screen. Otherwise, the + * frame on screen will be immediately reused for decoding which will then + * most often result in mixed images on screen, especially when decoding + * is faster than sending the image to the monitor, and/or when exchanging + * the overlay image is synced to retrace. + */ xxmc_add_recent_frame (this, frame); /* deinterlacing */ if ((frame->format == XINE_IMGFMT_XXMC) && @@ -1616,34 +1709,58 @@ 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) { XVMCLOCKDISPLAY( this->display ); XvMCSyncSurface( this->display, frame->xvmc_surf ); + XLockDisplay( this->display ); /* blocks XINE_GUI_SEND_DRAWABLE_CHANGED from changing drawable */ 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); + XUnlockDisplay( this->display ); /* unblocks XINE_GUI_SEND_DRAWABLE_CHANGED from changing drawable */ 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 ); + XLockDisplay( this->display ); /* blocks XINE_GUI_SEND_DRAWABLE_CHANGED from changing drawable */ + 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); + XUnlockDisplay( this->display ); /* unblocks XINE_GUI_SEND_DRAWABLE_CHANGED from changing drawable */ + XVMCUNLOCKDISPLAY( this->display ); + } } } else { XLockDisplay (this->display); @@ -1679,9 +1796,21 @@ static int xxmc_get_property (vo_driver_t *this_gen, int property) { case VO_PROP_WINDOW_HEIGHT: this->props[property].value = this->sc.gui_height; break; + case VO_PROP_OUTPUT_WIDTH: + this->props[property].value = this->sc.output_width; + break; + case VO_PROP_OUTPUT_HEIGHT: + this->props[property].value = this->sc.output_height; + break; + case VO_PROP_OUTPUT_XOFFSET: + this->props[property].value = this->sc.output_xoffset; + break; + case VO_PROP_OUTPUT_YOFFSET: + this->props[property].value = this->sc.output_yoffset; + break; } - lprintf("video_out_xxmc: property #%d = %d\n", property, this->props[property].value); + lprintf("%s: property #%d = %d\n", LOG_MODULE, property, this->props[property].value); return this->props[property].value; } @@ -1744,7 +1873,7 @@ static int xxmc_set_property (vo_driver_t *this_gen, case VO_PROP_INTERLACED: this->props[property].value = value; xprintf(this->xine, XINE_VERBOSITY_LOG, - "video_out_xxmc: VO_PROP_INTERLACED(%d)\n", this->props[property].value); + LOG_MODULE ": VO_PROP_INTERLACED(%d)\n", this->props[property].value); this->deinterlace_enabled = value; break; @@ -1754,7 +1883,7 @@ static int xxmc_set_property (vo_driver_t *this_gen, this->props[property].value = value; xprintf(this->xine, XINE_VERBOSITY_LOG, - "video_out_xxmc: VO_PROP_ASPECT_RATIO(%d)\n", this->props[property].value); + LOG_MODULE ": VO_PROP_ASPECT_RATIO(%d)\n", this->props[property].value); this->sc.user_ratio = value; xxmc_compute_ideal_size (this); @@ -1766,7 +1895,7 @@ static int xxmc_set_property (vo_driver_t *this_gen, if ((value >= XINE_VO_ZOOM_MIN) && (value <= XINE_VO_ZOOM_MAX)) { this->props[property].value = value; xprintf(this->xine, XINE_VERBOSITY_LOG, - "video_out_xxmc: VO_PROP_ZOOM_X = %d\n", this->props[property].value); + LOG_MODULE ": VO_PROP_ZOOM_X = %d\n", this->props[property].value); this->sc.zoom_factor_x = (double)value / (double)XINE_VO_ZOOM_STEP; @@ -1780,7 +1909,7 @@ static int xxmc_set_property (vo_driver_t *this_gen, if ((value >= XINE_VO_ZOOM_MIN) && (value <= XINE_VO_ZOOM_MAX)) { this->props[property].value = value; xprintf(this->xine, XINE_VERBOSITY_LOG, - "video_out_xxmc: VO_PROP_ZOOM_Y = %d\n", this->props[property].value); + LOG_MODULE ": VO_PROP_ZOOM_Y = %d\n", this->props[property].value); this->sc.zoom_factor_y = (double)value / (double)XINE_VO_ZOOM_STEP; @@ -1927,14 +2056,14 @@ static void xxmc_dispose (vo_driver_t *this_gen) { XLockDisplay (this->display); if(XvUngrabPort (this->display, this->xv_port, CurrentTime) != Success) { - xprintf (this->xine, XINE_VERBOSITY_DEBUG, "video_out_xxmc: xxmc_exit: XvUngrabPort() failed.\n"); + xprintf (this->xine, XINE_VERBOSITY_DEBUG, LOG_MODULE ": xxmc_exit: XvUngrabPort() failed.\n"); } XFreeGC(this->display, this->gc); XUnlockDisplay (this->display); 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; } @@ -1991,7 +2120,7 @@ static void xxmc_check_capability (xxmc_driver_t *this, this->props[property].atom, &int_default); xprintf(this->xine, XINE_VERBOSITY_DEBUG, - "video_out_xxmc: port attribute %s (%d) value is %d\n", str_prop, property, int_default); + LOG_MODULE ": port attribute %s (%d) value is %d\n", str_prop, property, int_default); /* * We enable autopaint by default. @@ -2053,7 +2182,7 @@ static void xxmc_update_XV_FILTER(void *this_gen, xine_cfg_entry_t *entry) { XUnlockDisplay(this->display); xprintf(this->xine, XINE_VERBOSITY_DEBUG, - "video_out_xxmc: bilinear scaling mode (XV_FILTER) = %d\n",xv_filter); + LOG_MODULE ": bilinear scaling mode (XV_FILTER) = %d\n",xv_filter); } static void xxmc_update_XV_DOUBLE_BUFFER(void *this_gen, xine_cfg_entry_t *entry) { @@ -2069,7 +2198,7 @@ static void xxmc_update_XV_DOUBLE_BUFFER(void *this_gen, xine_cfg_entry_t *entry XUnlockDisplay(this->display); xprintf(this->xine, XINE_VERBOSITY_DEBUG, - "video_out_xxmc: double buffering mode = %d\n", xv_double_buffer); + LOG_MODULE ": double buffering mode = %d\n", xv_double_buffer); } static void xxmc_update_xv_pitch_alignment(void *this_gen, xine_cfg_entry_t *entry) { @@ -2096,6 +2225,18 @@ static void xxmc_update_bob(void *this_gen, xine_cfg_entry_t *entry) { this->bob = entry->num_value; } +static void xxmc_update_disable_bob_for_progressive_frames(void *this_gen, xine_cfg_entry_t *entry) { + xxmc_driver_t *this = (xxmc_driver_t *) this_gen; + + this->disable_bob_for_progressive_frames = entry->num_value; +} + +static void xxmc_update_disable_bob_for_scaled_osd(void *this_gen, xine_cfg_entry_t *entry) { + xxmc_driver_t *this = (xxmc_driver_t *) this_gen; + + this->disable_bob_for_scaled_osd = entry->num_value; +} + static void checkXvMCCap( xxmc_driver_t *this, XvPortID xv_port) { @@ -2129,7 +2270,7 @@ static void checkXvMCCap( xxmc_driver_t *this, XvPortID xv_port) return; } xprintf (this->xine, XINE_VERBOSITY_DEBUG, - "video_out_xxmc: XvMC extension present.\n"); + LOG_MODULE ": XvMC extension present.\n"); surfaceInfo = XvMCListSurfaceTypes(this->display, xv_port, &numSurf); if (0 == surfaceInfo) { @@ -2145,7 +2286,7 @@ static void checkXvMCCap( xxmc_driver_t *this, XvPortID xv_port) curCap = this->xvmc_cap; xprintf (this->xine, XINE_VERBOSITY_DEBUG, - "video_out_xxmc: Found %d XvMC surface types\n",numSurf); + LOG_MODULE ": Found %d XvMC surface types\n", numSurf); for (i=0; i< numSurf; ++i) { curCap->mpeg_flags = 0; @@ -2169,10 +2310,10 @@ static void checkXvMCCap( xxmc_driver_t *this, XvPortID xv_port) curCap->sub_max_height = curInfo->subpicture_max_height; curCap->flags = curInfo->flags; xprintf (this->xine, XINE_VERBOSITY_DEBUG, - "video_out_xxmc: Surface type %d: Max size: %d %d.\n", + LOG_MODULE ": Surface type %d: Max size: %d %d.\n", i,curCap->max_width,curCap->max_height); xprintf (this->xine, XINE_VERBOSITY_DEBUG, - "video_out_xxmc: Surface type %d: Max subpic size: %d %d.\n", + LOG_MODULE ": Surface type %d: Max subpic size: %d %d.\n", i,curCap->sub_max_width,curCap->sub_max_height); curCap->type_id = curInfo->surface_type_id; @@ -2181,21 +2322,18 @@ static void checkXvMCCap( xxmc_driver_t *this, XvPortID xv_port) curCap->subPicType.id = 0; if (formatValues) { xprintf (this->xine, XINE_VERBOSITY_DEBUG, - "video_out_xxmc: Surface type %d: Found %d XvMC subpicture " - "types\n",i,numSub); + LOG_MODULE ": Surface type %d: Found %d XvMC subpicture types\n",i,numSub); for (j = 0; j<numSub; ++j) { if (formatValues[j].id == FOURCC_IA44) { curCap->subPicType = formatValues[j]; xprintf (this->xine, XINE_VERBOSITY_DEBUG, - "video_out_xxmc: Surface type %d: Detected and using " - "IA44 subpicture type.\n",i); + LOG_MODULE ": Surface type %d: Detected and using IA44 subpicture type.\n",i); /* Prefer IA44 */ break; } else if (formatValues[j].id == FOURCC_AI44) { curCap->subPicType = formatValues[j]; xprintf (this->xine, XINE_VERBOSITY_DEBUG, - "video_out_xxmc: Surface type %d: Detected AI44 " - "subpicture type.\n",i); + LOG_MODULE ": Surface type %d: Detected AI44 subpicture type.\n",i); } } } @@ -2226,9 +2364,8 @@ static void checkXvMCCap( xxmc_driver_t *this, XvPortID xv_port) free(this->xvmc_cap); this->xvmc_cap = 0; xprintf (this->xine, XINE_VERBOSITY_DEBUG, - "video_out_xxmc: Apparent attempt to use a direct XvMC " - "context\nvideo_out_xxmc: on a remote display. " - "Falling back to XV.\n"); + LOG_MODULE ": Apparent attempt to use a direct XvMC context on a remote display.\n" + LOG_MODULE ": Falling back to Xv.\n"); XVMCUNLOCKDISPLAY( this->display ); xvmc_context_writer_unlock( &this->xvmc_lock ); return; @@ -2284,7 +2421,7 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi XLockDisplay(this->display); if (Success != XvQueryExtension(this->display, &ver,&rel, &req, &ev,&err)) { - xprintf (class->xine, XINE_VERBOSITY_LOG, _("video_out_xxmc: Xv extension not present.\n")); + xprintf (class->xine, XINE_VERBOSITY_LOG, _("%s: Xv extension not present.\n"), LOG_MODULE); XUnlockDisplay(this->display); return NULL; } @@ -2294,7 +2431,7 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi */ if (Success != XvQueryAdaptors(this->display,DefaultRootWindow(this->display), &adaptors, &adaptor_info)) { - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "video_out_xxmc: XvQueryAdaptors failed.\n"); + xprintf(class->xine, XINE_VERBOSITY_DEBUG, LOG_MODULE ": XvQueryAdaptors failed.\n"); XUnlockDisplay(this->display); return NULL; } @@ -2321,8 +2458,9 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi if (!xv_port) { xprintf(class->xine, XINE_VERBOSITY_LOG, - _("video_out_xxmc: Xv extension is present but I couldn't find a usable yuv12 port.\n" - " Looks like your graphics hardware driver doesn't support Xv?!\n")); + _("%s: Xv extension is present but I couldn't find a usable yuv12 port.\n" + "\tLooks like your graphics hardware driver doesn't support Xv?!\n"), + LOG_MODULE); /* XvFreeAdaptorInfo (adaptor_info); this crashed on me (gb)*/ XUnlockDisplay(this->display); @@ -2330,8 +2468,8 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi } else xprintf(class->xine, XINE_VERBOSITY_LOG, - _("video_out_xxmc: using Xv port %ld from adaptor %s for hardware " - "colorspace conversion and scaling.\n"), xv_port, + _("%s: using Xv port %ld from adaptor %s for hardware " + "colour space conversion and scaling.\n"), LOG_MODULE, xv_port, adaptor_info[adaptor_num].name); XUnlockDisplay(this->display); @@ -2407,7 +2545,7 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi if((attr[k].flags & XvSettable) && (attr[k].flags & XvGettable)) { if(!strcmp(attr[k].name, "XV_HUE")) { if (!strncmp(adaptor_info[adaptor_num].name, "NV", 2)) { - xprintf (this->xine, XINE_VERBOSITY_NONE, "video_out_xxmc: ignoring broken XV_HUE settings on NVidia cards\n"); + xprintf (this->xine, XINE_VERBOSITY_NONE, LOG_MODULE ": ignoring broken XV_HUE settings on NVidia cards\n"); } else { xxmc_check_capability (this, VO_PROP_HUE, attr[k], adaptor_info[adaptor_num].base_id, "XV_HUE", @@ -2442,7 +2580,7 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi adaptor_info[adaptor_num].base_id, "XV_AUTOPAINT_COLORKEY", "video.device.xv_autopaint_colorkey", _("autopaint colour key"), - _("Make Xv autopaint its colorkey.")); + _("Make Xv autopaint its colour key.")); } else if(!strcmp(attr[k].name, "XV_FILTER")) { int xv_filter; @@ -2477,7 +2615,7 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi XFree(attr); } else - xprintf(this->xine, XINE_VERBOSITY_DEBUG, "video_out_xxmc: no port attributes defined.\n"); + xprintf(this->xine, XINE_VERBOSITY_DEBUG, LOG_MODULE ": no port attributes defined.\n"); XvFreeAdaptorInfo(adaptor_info); /* @@ -2506,12 +2644,12 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi this->xv_format_yv12 = fo[i].id; this->capabilities |= VO_CAP_YV12; xprintf(this->xine, XINE_VERBOSITY_LOG, - _("video_out_xxmc: this adaptor supports the yv12 format.\n")); + _("%s: this adaptor supports the yv12 format.\n"), LOG_MODULE); } else if (fo[i].id == XINE_IMGFMT_YUY2) { this->xv_format_yuy2 = fo[i].id; this->capabilities |= VO_CAP_YUY2; xprintf(this->xine, XINE_VERBOSITY_LOG, - _("video_out_xxmc: this adaptor supports the yuy2 format.\n")); + _("%s: this adaptor supports the yuy2 format.\n"), LOG_MODULE); } } @@ -2554,25 +2692,39 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi 10, xxmc_update_cpu_save, this); this->reverse_nvidia_palette = config->register_bool (config, "video.device.xvmc_nvidia_color_fix", 0, - _("Fix buggy NVIDIA XvMC subpicture colors"), - _("There's a bug in NVIDIA's XvMC lib that makes red OSD colors\n" + _("Fix buggy NVIDIA XvMC subpicture colours"), + _("There's a bug in NVIDIA's XvMC lib that makes red OSD colours\n" "look blue and vice versa. This option provides a workaround.\n"), 10, xxmc_update_nvidia_fix, this); this->bob = config->register_bool (config, "video.device.xvmc_bob_deinterlacing", 0, _("Use bob as accelerated deinterlace method."), _("When interlacing is enabled for hardware accelerated frames,\n" - "Alternate between top and bottom field at double the frame rate.\n"), + "alternate between top and bottom field at double the frame rate.\n"), 10, xxmc_update_bob, this); + this->disable_bob_for_progressive_frames = + config->register_bool (config, "video.device.xvmc_disable_bob_deinterlacing_for_progressive_frames", 0, + _("Don't use bob deinterlacing for progressive frames."), + _("Progressive frames don't need deinterlacing, so disabling it on\n" + "demand should result in a better picture.\n"), + 10, xxmc_update_disable_bob_for_progressive_frames, this); + + this->disable_bob_for_scaled_osd = + config->register_bool (config, "video.device.xvmc_disable_bob_deinterlacing_for_scaled_osd", 0, + _("Don't use bob deinterlacing while a scaled OSD is active."), + _("Bob deinterlacing adds some noise to horizontal lines, so disabling it\n" + "on demand should result in a better OSD picture.\n"), + 10, xxmc_update_disable_bob_for_scaled_osd, this); + this->deinterlace_enabled = 0; this->cur_field = XVMC_FRAME_PICTURE; #ifdef HAVE_VLDXVMC - printf("video_out_xxmc: Unichrome CPU saving is %s.\n", + printf("%s: Unichrome CPU saving is %s.\n", LOG_MODULE, (this->cpu_save_enabled) ? "on":"off"); #else - printf("video_out_xxmc: warning - compiled with no vld extensions.\n"); + printf("%s: warning - compiled with no vld extensions.\n", LOG_MODULE); #endif this->props[VO_PROP_MAX_NUM_FRAMES].value = (use_more_frames) ? 15:8; this->cpu_saver = 0.; @@ -2609,28 +2761,13 @@ static vo_driver_t *open_plugin (video_driver_class_t *class_gen, const void *vi /* * class functions */ - -static char* get_identifier (video_driver_class_t *this_gen) { - return "XxMC"; -} - -static char* get_description (video_driver_class_t *this_gen) { - return _("xine video output plugin using the MIT X video extension"); -} - -static void dispose_class (video_driver_class_t *this_gen) { - xxmc_class_t *this = (xxmc_class_t *) this_gen; - - free (this); -} - static void *init_class (xine_t *xine, void *visual_gen) { xxmc_class_t *this = (xxmc_class_t *) xine_xmalloc (sizeof (xxmc_class_t)); this->driver_class.open_plugin = open_plugin; - this->driver_class.get_identifier = get_identifier; - this->driver_class.get_description = get_description; - this->driver_class.dispose = dispose_class; + this->driver_class.identifier = "XxMC"; + this->driver_class.description = N_("xine video output plugin using the MIT X video extension"); + this->driver_class.dispose = default_video_driver_class_dispose; this->config = xine->config; this->xine = xine; @@ -2652,7 +2789,7 @@ static const vo_info_t vo_info_xxmc = { const plugin_info_t xine_plugin_info[] EXPORTED = { /* type, API, "name", version, special_info, init_function */ - { PLUGIN_VIDEO_OUT, 21, "xxmc", XINE_VERSION_CODE, &vo_info_xxmc, init_class }, + { PLUGIN_VIDEO_OUT, 22, "xxmc", XINE_VERSION_CODE, &vo_info_xxmc, init_class }, { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; |