? 32bit ? default ? enterprise ? prakesh Index: configure.ac =================================================================== RCS file: /cvsroot/xine/xine-lib/configure.ac,v retrieving revision 1.459 diff -u -B -r1.459 configure.ac --- configure.ac 28 Jan 2007 23:48:29 -0000 1.459 +++ configure.ac 7 Feb 2007 02:41:31 -0000 @@ -894,6 +894,46 @@ dnl --------------------------------------------- +dnl Check for xcb +dnl --------------------------------------------- +AC_ARG_WITH([xcb], AC_HELP_STRING([--without-xcb], [Doesn't build XCB video out plugins])) + +if test "x$with_xcb" != "xno"; then + PKG_CHECK_MODULES([XCB], [xcb-shape >= 1.0], [have_xcb="yes"], [have_xcb="no"]) +fi + +AC_SUBST(XCB_CFLAGS) +AC_SUBST(XCB_LIBS) +AM_CONDITIONAL(HAVE_XCB, test "x$have_xcb" = "xyes" ) + + +dnl --------------------------------------------- +dnl Check for xcb-shm +dnl --------------------------------------------- + +if test "x$have_xcb" = "xyes"; then + PKG_CHECK_MODULES([XCBSHM], [xcb-shm], [have_xcbshm="yes"], [have_xcbshm="no"]) +fi + +AC_SUBST(XCBSHM_CFLAGS) +AC_SUBST(XCBSHM_LIBS) +AM_CONDITIONAL(HAVE_XCBSHM, test "x$have_xcbshm" = "xyes" ) + + +dnl --------------------------------------------- +dnl Check for xcb-xv +dnl --------------------------------------------- + +if test "x$have_xcb" = "xyes"; then + PKG_CHECK_MODULES([XCBXV], [xcb-xv], [have_xcbxv="yes"], [have_xcbxv="no"]) +fi + +AC_SUBST(XCBXV_CFLAGS) +AC_SUBST(XCBXV_LIBS) +AM_CONDITIONAL(HAVE_XCBXV, test "x$have_xcbxv" = "xyes" ) + + +dnl --------------------------------------------- dnl Checks for Xinerama extension dnl --------------------------------------------- @@ -2959,6 +2999,16 @@ fi fi fi +if test "x$have_xcb" = "xyes"; then + dnl xcb-shm + if test "x$have_xcbshm" = "xyes"; then + echo " - xcb-shm (X shared memory using XCB)" + fi + dnl xcb-xv + if test "x$have_xcbxv" = "xyes"; then + echo " - xcb-xv (XVideo using XCB)" + fi +fi if test "x$no_aalib" != "xyes"; then echo " - aa (Ascii ART)" fi Index: include/xine.h.in =================================================================== RCS file: /cvsroot/xine/xine-lib/include/xine.h.in,v retrieving revision 1.162 diff -u -B -r1.162 xine.h.in --- include/xine.h.in 21 Dec 2006 00:09:18 -0000 1.162 +++ include/xine.h.in 7 Feb 2007 02:41:33 -0000 @@ -176,6 +176,7 @@ #define XINE_VISUAL_TYPE_DIRECTX 7 /* used by the win32/msvc port */ #define XINE_VISUAL_TYPE_CACA 8 #define XINE_VISUAL_TYPE_MACOSX 9 +#define XINE_VISUAL_TYPE_XCB 11 /* * free all resources, close all plugins, close engine. @@ -1192,6 +1193,82 @@ } x11_visual_t; /* + * this is the visual data struct any xcb gui + * must supply to the xine_open_video_driver call + * ("data" parameter) + */ +typedef struct { + + /* some information about the display */ + void *connection; /* xcb_connection_t */ + void *screen; /* xcb_screen_t */ + + /* window to display the video in / on */ + unsigned int window; /* xcb_window_t */ + + void *user_data; + + /* + * dest size callback + * + * this will be called by the video driver to find out + * how big the video output area size will be for a + * given video size. The ui should _not_ adjust it's + * video out area, just do some calculations and return + * the size. This will be called for every frame, ui + * implementation should be fast. + * dest_pixel_aspect should be set to the used display pixel aspect. + * NOTE: Semantics has changed: video_width and video_height + * are no longer pixel aspect corrected. Get the old semantics + * in the UI with + * *dest_pixel_aspect = display_pixel_aspect; + * if (video_pixel_aspect >= display_pixel_aspect) + * video_width = video_width * video_pixel_aspect / display_pixel_aspect + .5; + * else + * video_height = video_height * display_pixel_aspect / video_pixel_aspect + .5; + */ + void (*dest_size_cb) (void *user_data, + int video_width, int video_height, + double video_pixel_aspect, + int *dest_width, int *dest_height, + double *dest_pixel_aspect); + + /* + * frame output callback + * + * this will be called by the video driver for every frame + * it's about to draw. ui can adapt it's size if necessary + * here. + * note: the ui doesn't have to adjust itself to this + * size, this is just to be taken as a hint. + * ui must return the actual size of the video output + * area and the video output driver will do it's best + * to adjust the video frames to that size (while + * preserving aspect ratio and stuff). + * dest_x, dest_y: offset inside window + * dest_width, dest_height: available drawing space + * dest_pixel_aspect: display pixel aspect + * win_x, win_y: window absolute screen position + * NOTE: Semantics has changed: video_width and video_height + * are no longer pixel aspect corrected. Get the old semantics + * in the UI with + * *dest_pixel_aspect = display_pixel_aspect; + * if (video_pixel_aspect >= display_pixel_aspect) + * video_width = video_width * video_pixel_aspect / display_pixel_aspect + .5; + * else + * video_height = video_height * display_pixel_aspect / video_pixel_aspect + .5; + */ + void (*frame_output_cb) (void *user_data, + int video_width, int video_height, + double video_pixel_aspect, + int *dest_x, int *dest_y, + int *dest_width, int *dest_height, + double *dest_pixel_aspect, + int *win_x, int *win_y); + +} xcb_visual_t; + +/* * this is the visual data struct any fb gui * may supply to the xine_open_video_driver call * ("data" parameter) to get frame_output_cd calls Index: src/video_out/Makefile.am =================================================================== RCS file: /cvsroot/xine/xine-lib/src/video_out/Makefile.am,v retrieving revision 1.128 diff -u -B -r1.128 Makefile.am --- src/video_out/Makefile.am 28 Jan 2007 17:35:01 -0000 1.128 +++ src/video_out/Makefile.am 7 Feb 2007 02:41:36 -0000 @@ -37,6 +37,16 @@ endif endif +if HAVE_XCB +XCBOSD = xcbosd.c +if HAVE_XCBSHM +xcbshm_module = xineplug_vo_out_xcbshm.la +endif +if HAVE_XCBXV +xcbxv_module = xineplug_vo_out_xcbxv.la +endif +endif + if HAVE_VIDIX vidix_module = xineplug_vo_out_vidix.la endif @@ -86,8 +96,20 @@ $(caca_module) \ $(macosx_module) \ $(xxmc_module) \ + $(xcbshm_module) \ + $(xcbxv_module) \ xineplug_vo_out_none.la +xineplug_vo_out_xcbshm_la_SOURCES = yuv2rgb.c yuv2rgb_mmx.c yuv2rgb_mlib.c video_out_xcbshm.c $(XCBOSD) +xineplug_vo_out_xcbshm_la_LIBADD = $(MLIB_LIBS) $(XINE_LIB) $(THREAD_LIBS) $(XCB_LIBS) $(XCBSHM_LIBS) +xineplug_vo_out_xcbshm_la_CFLAGS = $(VISIBILITY_FLAG) $(MLIB_CFLAGS) $(XCB_CFLAGS) $(XCBSHM_CFLAGS) +xineplug_vo_out_xcbshm_la_LDFLAGS = -avoid-version -module + +xineplug_vo_out_xcbxv_la_SOURCES = deinterlace.c video_out_xcbxv.c $(XCBOSD) +xineplug_vo_out_xcbxv_la_LIBADD = $(XINE_LIB) $(THREAD_LIBS) $(XCBXV_LIBS) $(XCB_LIBS) +xineplug_vo_out_xcbxv_la_CFLAGS = $(VISIBILITY_FLAG) $(XCB_CFLAGS) $(XCBXV_CFLAGS) +xineplug_vo_out_xcbxv_la_LDFLAGS = -avoid-version -module + xineplug_vo_out_xshm_la_SOURCES = yuv2rgb.c yuv2rgb_mmx.c yuv2rgb_mlib.c \ video_out_xshm.c $(X11OSD) xineplug_vo_out_xshm_la_LIBADD = $(MLIB_LIBS) $(X_LIBS) -lXext $(X_PRE_LIBS) -lX11 $(XINE_LIB) $(THREAD_LIBS) @@ -192,4 +214,4 @@ -Wl,-framework -Wl,Cocoa -framework Cocoa -framework OpenGL noinst_HEADERS = deinterlace.h video_out_syncfb.h \ - yuv2rgb.h x11osd.h + yuv2rgb.h x11osd.h xcbosd.h Index: src/video_out/video_out_xcbshm.c =================================================================== RCS file: src/video_out/video_out_xcbshm.c diff -N src/video_out/video_out_xcbshm.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/video_out/video_out_xcbshm.c 7 Feb 2007 02:41:40 -0000 @@ -0,0 +1,1274 @@ +/* + * Copyright (C) 2000-2003, 2007 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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: xine-lib-1.1.4-xcb.patch,v 1.1 2007-05-08 20:43:46 niro Exp $ + * + * video_out_xcbshm.c, X11 shared memory extension interface for xine + * + * based on mpeg2dec code from + * Aaron Holtzman + * + * xine-specific code by Guenter Bartsch + * + * ported to xcb by Christoph Pfister - Feb 2007 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include "xine.h" +#include "video_out.h" + +#include + +#include + +#include +#include +#include + +#include +#include + +#define LOG_MODULE "video_out_xcbshm" +#define LOG_VERBOSE +/* +#define LOG +*/ + +#include "xine_internal.h" +#include "yuv2rgb.h" +#include "xineutils.h" +#include "vo_scale.h" +#include "xcbosd.h" + +typedef struct { + vo_frame_t vo_frame; + + /* frame properties as delivered by the decoder: */ + /* obs: for width/height use vo_scale_t struct */ + int format; + int flags; + + vo_scale_t sc; + + uint8_t *image; + int bytes_per_line; + xcb_shm_seg_t shmseg; + + uint8_t *chunk[3]; /* mem alloc by xmalloc_aligned */ + + yuv2rgb_t *yuv2rgb; /* yuv2rgb converter set up for this frame */ + uint8_t *rgb_dst; + +} xshm_frame_t; + +typedef struct { + + vo_driver_t vo_driver; + + /* xcb / shm related stuff */ + xcb_connection_t *connection; + xcb_screen_t *screen; + xcb_window_t window; + xcb_gcontext_t gc; + int depth; + int bpp; + int scanline_pad; + int use_shm; + + int yuv2rgb_brightness; + int yuv2rgb_contrast; + int yuv2rgb_saturation; + uint8_t *yuv2rgb_cmap; + yuv2rgb_factory_t *yuv2rgb_factory; + + vo_scale_t sc; + + xshm_frame_t *cur_frame; + xcbosd *xoverlay; + int ovl_changed; + + xine_t *xine; + + alphablend_t alphablend_extra_data; + + pthread_mutex_t main_mutex; + +} xshm_driver_t; + +typedef struct { + video_driver_class_t driver_class; + + config_values_t *config; + xine_t *xine; +} xshm_class_t; + + +/* + * allocate an XImage, try XShm first but fall back to + * plain X11 if XShm should fail + */ +static void create_ximage(xshm_driver_t *this, xshm_frame_t *frame, int width, int height) +{ + frame->bytes_per_line = ((this->bpp * width + this->scanline_pad - 1) & + (~(this->scanline_pad - 1))) >> 3; + + if (this->use_shm) { + int shmid; + xcb_void_cookie_t shm_attach_cookie; + xcb_generic_error_t *generic_error; + + /* + * try shm + */ + + shmid = shmget(IPC_PRIVATE, frame->bytes_per_line * height, IPC_CREAT | 0777); + + if (shmid < 0) { + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("video_out_xshm: %s: allocating image\n" + "video_out_xshm: => not using MIT Shared Memory extension.\n"), strerror(errno)); + goto shm_fail1; + } + + frame->image = shmat(shmid, 0, 0); + + if (frame->image == ((void *) -1)) { + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("video_out_xshm: shared memory error (address error) when allocating image \n" + "video_out_xshm: => not using MIT Shared Memory extension.\n")); + goto shm_fail2; + } + + frame->shmseg = xcb_generate_id(this->connection); + shm_attach_cookie = xcb_shm_attach_checked(this->connection, frame->shmseg, shmid, 0); + generic_error = xcb_request_check(this->connection, shm_attach_cookie); + + if (generic_error != NULL) { + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("video_out_xshm: x11 error during shared memory XImage creation\n" + "video_out_xshm: => not using MIT Shared Memory extension.\n")); + free(generic_error); + goto shm_fail3; + } + + /* + * Now that the Xserver has learned about and attached to the + * shared memory segment, delete it. It's actually deleted by + * the kernel when all users of that segment have detached from + * it. Gives an automatic shared memory cleanup in case we crash. + */ + + shmctl(shmid, IPC_RMID, 0); + + return; + + shm_fail3: + frame->shmseg = 0; + shmdt(frame->image); + shm_fail2: + shmctl(shmid, IPC_RMID, 0); + shm_fail1: + this->use_shm = 0; + } + + /* + * fall back to plain X11 if necessary + */ + + frame->image = malloc(frame->bytes_per_line * height); +} + +static void dispose_ximage(xshm_driver_t *this, xshm_frame_t *frame) +{ + if (frame->shmseg) { + xcb_shm_detach(this->connection, frame->shmseg); + frame->shmseg = 0; + shmdt(frame->image); + } else + free(frame->image); + frame->image = NULL; +} + + +/* + * and now, the driver functions + */ + +static uint32_t xshm_get_capabilities (vo_driver_t *this_gen) { + xshm_driver_t *this = (xshm_driver_t *) this_gen; + uint32_t capabilities = VO_CAP_YV12 | VO_CAP_YUY2; + + if( this->xoverlay ) + capabilities |= VO_CAP_UNSCALED_OVERLAY; + + return capabilities; +} + +static void xshm_frame_proc_slice (vo_frame_t *vo_img, uint8_t **src) { + xshm_frame_t *frame = (xshm_frame_t *) vo_img ; + /*xshm_driver_t *this = (xshm_driver_t *) vo_img->driver; */ + + vo_img->proc_called = 1; + + if( frame->vo_frame.crop_left || frame->vo_frame.crop_top || + frame->vo_frame.crop_right || frame->vo_frame.crop_bottom ) + { + /* we don't support crop, so don't even waste cpu cycles. + * cropping will be performed by video_out.c + */ + return; + } + + lprintf ("copy... (format %d)\n", frame->format); + + if (frame->format == XINE_IMGFMT_YV12) + frame->yuv2rgb->yuv2rgb_fun (frame->yuv2rgb, frame->rgb_dst, + src[0], src[1], src[2]); + else + frame->yuv2rgb->yuy22rgb_fun (frame->yuv2rgb, frame->rgb_dst, + src[0]); + + lprintf ("copy...done\n"); +} + +static void xshm_frame_field (vo_frame_t *vo_img, int which_field) { + xshm_frame_t *frame = (xshm_frame_t *) vo_img ; + /* xshm_driver_t *this = (xshm_driver_t *) vo_img->driver; */ + + switch (which_field) { + case VO_TOP_FIELD: + frame->rgb_dst = frame->image; + break; + case VO_BOTTOM_FIELD: + frame->rgb_dst = frame->image + frame->bytes_per_line; + break; + case VO_BOTH_FIELDS: + frame->rgb_dst = frame->image; + break; + } + + frame->yuv2rgb->next_slice (frame->yuv2rgb, NULL); +} + +static void xshm_frame_dispose (vo_frame_t *vo_img) { + xshm_frame_t *frame = (xshm_frame_t *) vo_img ; + xshm_driver_t *this = (xshm_driver_t *) vo_img->driver; + + if (frame->image) { + pthread_mutex_lock(&this->main_mutex); + dispose_ximage(this, frame); + pthread_mutex_unlock(&this->main_mutex); + } + + frame->yuv2rgb->dispose (frame->yuv2rgb); + + free (frame->chunk[0]); + free (frame->chunk[1]); + free (frame->chunk[2]); + free (frame); +} + + +static vo_frame_t *xshm_alloc_frame (vo_driver_t *this_gen) { + xshm_frame_t *frame; + xshm_driver_t *this = (xshm_driver_t *) this_gen; + + frame = (xshm_frame_t *) xine_xmalloc (sizeof (xshm_frame_t)); + if (!frame) + return NULL; + + memcpy (&frame->sc, &this->sc, sizeof(vo_scale_t)); + + pthread_mutex_init (&frame->vo_frame.mutex, NULL); + + /* + * supply required functions/fields + */ + + frame->vo_frame.proc_slice = xshm_frame_proc_slice; + frame->vo_frame.proc_frame = NULL; + frame->vo_frame.field = xshm_frame_field; + frame->vo_frame.dispose = xshm_frame_dispose; + frame->vo_frame.driver = this_gen; + + /* + * colorspace converter for this frame + */ + + frame->yuv2rgb = this->yuv2rgb_factory->create_converter (this->yuv2rgb_factory); + + return (vo_frame_t *) frame; +} + +static void xshm_compute_ideal_size (xshm_driver_t *this, xshm_frame_t *frame) { + _x_vo_scale_compute_ideal_size( &frame->sc ); +} + +static void xshm_compute_rgb_size (xshm_driver_t *this, xshm_frame_t *frame) { + _x_vo_scale_compute_output_size( &frame->sc ); + + /* avoid problems in yuv2rgb */ + if (frame->sc.output_height < 1) + frame->sc.output_height = 1; + if (frame->sc.output_width < 8) + frame->sc.output_width = 8; + if (frame->sc.output_width & 1) /* yuv2rgb_mlib needs an even YUV2 width */ + frame->sc.output_width++; + + lprintf("frame source (%d) %d x %d => screen output %d x %d%s\n", + frame->vo_frame.id, + frame->sc.delivered_width, frame->sc.delivered_height, + frame->sc.output_width, frame->sc.output_height, + ( frame->sc.delivered_width != frame->sc.output_width + || frame->sc.delivered_height != frame->sc.output_height + ? ", software scaling" + : "" ) + ); +} + +static void xshm_update_frame_format (vo_driver_t *this_gen, + vo_frame_t *frame_gen, + uint32_t width, uint32_t height, + double ratio, int format, int flags) { + xshm_driver_t *this = (xshm_driver_t *) this_gen; + xshm_frame_t *frame = (xshm_frame_t *) frame_gen; + int do_adapt; + int gui_width; + int gui_height; + double gui_pixel_aspect; + + flags &= VO_BOTH_FIELDS; + + /* ask gui what output size we'll have for this frame */ + /* get the gui_pixel_aspect before calling xshm_compute_ideal_size() */ + /* note: gui_width and gui_height may be bogus because we may have not yet*/ + /* updated video_pixel_aspect (see _x_vo_scale_compute_ideal_size). */ + frame->sc.dest_size_cb (frame->sc.user_data, width, height, + frame->sc.video_pixel_aspect, + &gui_width, &gui_height, + &gui_pixel_aspect); + + /* find out if we need to adapt this frame */ + do_adapt = 0; + + if ((width != frame->sc.delivered_width) + || (height != frame->sc.delivered_height) + || (ratio != frame->sc.delivered_ratio) + || (flags != frame->flags) + || (format != frame->format) + || (gui_pixel_aspect != frame->sc.gui_pixel_aspect) + || (this->sc.user_ratio != frame->sc.user_ratio)) { + + do_adapt = 1; + + lprintf ("frame format (from decoder) has changed => adapt\n"); + + frame->sc.delivered_width = width; + frame->sc.delivered_height = height; + frame->sc.delivered_ratio = ratio; + frame->sc.gui_pixel_aspect = gui_pixel_aspect; + frame->flags = flags; + frame->format = format; + frame->sc.user_ratio = this->sc.user_ratio; + + xshm_compute_ideal_size (this, frame); + + /* now we have updated video_aspect_pixel we use the callback */ + /* again to obtain the correct gui_width and gui_height values. */ + frame->sc.dest_size_cb (frame->sc.user_data, width, height, + frame->sc.video_pixel_aspect, + &gui_width, &gui_height, + &gui_pixel_aspect); + } + + if ((frame->sc.gui_width != gui_width) || + (frame->sc.gui_height != gui_height) || + do_adapt) { + + do_adapt = 1; + frame->sc.gui_width = gui_width; + frame->sc.gui_height = gui_height; + + xshm_compute_rgb_size (this, frame); + + lprintf ("gui_size has changed => adapt\n"); + } + + + /* ok, now do what we have to do */ + + if (do_adapt) { + + lprintf ("updating frame to %d x %d\n", + frame->sc.output_width, frame->sc.output_height); + + pthread_mutex_lock(&this->main_mutex); + + /* + * (re-) allocate XImage + */ + + if (frame->image) { + + dispose_ximage(this, frame); + + if (frame->chunk[0]){ + free (frame->chunk[0]); + frame->chunk[0] = NULL; + } + if (frame->chunk[1]) { + free (frame->chunk[1]); + frame->chunk[1] = NULL; + } + if (frame->chunk[2]) { + free (frame->chunk[2]); + frame->chunk[2] = NULL; + } + } + + create_ximage(this, frame, frame->sc.output_width, frame->sc.output_height); + + pthread_mutex_unlock(&this->main_mutex); + + if (format == XINE_IMGFMT_YV12) { + frame->vo_frame.pitches[0] = 8*((width + 7) / 8); + frame->vo_frame.pitches[1] = 8*((width + 15) / 16); + frame->vo_frame.pitches[2] = 8*((width + 15) / 16); + frame->vo_frame.base[0] = xine_xmalloc_aligned (16, frame->vo_frame.pitches[0] * height, (void **) &frame->chunk[0]); + frame->vo_frame.base[1] = xine_xmalloc_aligned (16, frame->vo_frame.pitches[1] * ((height+1)/2), (void **) &frame->chunk[1]); + frame->vo_frame.base[2] = xine_xmalloc_aligned (16, frame->vo_frame.pitches[2] * ((height+1)/2), (void **) &frame->chunk[2]); + } else { + frame->vo_frame.pitches[0] = 8*((width + 3) / 4); + frame->vo_frame.base[0] = xine_xmalloc_aligned (16, frame->vo_frame.pitches[0] * height, (void **) &frame->chunk[0]); + frame->chunk[1] = NULL; + frame->chunk[2] = NULL; + } + + lprintf ("stripe out_ht=%i, deliv_ht=%i\n", + frame->sc.output_height, frame->sc.delivered_height); + + /* + * set up colorspace converter + */ + + switch (flags) { + case VO_TOP_FIELD: + case VO_BOTTOM_FIELD: + frame->yuv2rgb->configure (frame->yuv2rgb, + frame->sc.delivered_width, + frame->sc.delivered_height, + 2*frame->vo_frame.pitches[0], + 2*frame->vo_frame.pitches[1], + frame->sc.output_width, + frame->sc.output_height, + frame->bytes_per_line*2); + break; + case VO_BOTH_FIELDS: + frame->yuv2rgb->configure (frame->yuv2rgb, + frame->sc.delivered_width, + frame->sc.delivered_height, + frame->vo_frame.pitches[0], + frame->vo_frame.pitches[1], + frame->sc.output_width, + frame->sc.output_height, + frame->bytes_per_line); + break; + } + } + + xshm_frame_field ((vo_frame_t *)frame, flags); +} + +static void xshm_overlay_clut_yuv2rgb(xshm_driver_t *this, vo_overlay_t *overlay, + xshm_frame_t *frame) { + size_t i; + clut_t* clut = (clut_t*) overlay->color; + + if (!overlay->rgb_clut) { + for (i = 0; i < sizeof(overlay->color)/sizeof(overlay->color[0]); i++) { + *((uint32_t *)&clut[i]) = + frame->yuv2rgb->yuv2rgb_single_pixel_fun (frame->yuv2rgb, + clut[i].y, clut[i].cb, clut[i].cr); + } + overlay->rgb_clut++; + } + if (!overlay->hili_rgb_clut) { + clut = (clut_t*) overlay->hili_color; + for (i = 0; i < sizeof(overlay->color)/sizeof(overlay->color[0]); i++) { + *((uint32_t *)&clut[i]) = + frame->yuv2rgb->yuv2rgb_single_pixel_fun(frame->yuv2rgb, + clut[i].y, clut[i].cb, clut[i].cr); + } + overlay->hili_rgb_clut++; + } +} + +static void xshm_overlay_begin (vo_driver_t *this_gen, + vo_frame_t *frame_gen, int changed) { + xshm_driver_t *this = (xshm_driver_t *) this_gen; + + this->ovl_changed += changed; + + if( this->ovl_changed && this->xoverlay ) { + pthread_mutex_lock(&this->main_mutex); + xcbosd_clear(this->xoverlay); + pthread_mutex_unlock(&this->main_mutex); + } + + this->alphablend_extra_data.offset_x = frame_gen->overlay_offset_x; + this->alphablend_extra_data.offset_y = frame_gen->overlay_offset_y; +} + +static void xshm_overlay_end (vo_driver_t *this_gen, vo_frame_t *vo_img) { + xshm_driver_t *this = (xshm_driver_t *) this_gen; + + if( this->ovl_changed && this->xoverlay ) { + pthread_mutex_lock(&this->main_mutex); + xcbosd_expose(this->xoverlay); + pthread_mutex_unlock(&this->main_mutex); + } + + this->ovl_changed = 0; +} + +static void xshm_overlay_blend (vo_driver_t *this_gen, + vo_frame_t *frame_gen, vo_overlay_t *overlay) { + xshm_driver_t *this = (xshm_driver_t *) this_gen; + xshm_frame_t *frame = (xshm_frame_t *) frame_gen; + + /* Alpha Blend here */ + if (overlay->rle) { + if( overlay->unscaled ) { + if( this->ovl_changed && this->xoverlay ) { + pthread_mutex_lock(&this->main_mutex); + xcbosd_blend(this->xoverlay, overlay); + pthread_mutex_unlock(&this->main_mutex); + } + } else { + if (!overlay->rgb_clut || !overlay->hili_rgb_clut) + xshm_overlay_clut_yuv2rgb (this, overlay, frame); + + switch (this->bpp) { + case 16: + _x_blend_rgb16(frame->image, overlay, + frame->sc.output_width, frame->sc.output_height, + frame->sc.delivered_width, frame->sc.delivered_height, + &this->alphablend_extra_data); + break; + case 24: + _x_blend_rgb24(frame->image, overlay, + frame->sc.output_width, frame->sc.output_height, + frame->sc.delivered_width, frame->sc.delivered_height, + &this->alphablend_extra_data); + break; + case 32: + _x_blend_rgb32(frame->image, overlay, + frame->sc.output_width, frame->sc.output_height, + frame->sc.delivered_width, frame->sc.delivered_height, + &this->alphablend_extra_data); + break; + default: + xprintf(this->xine, XINE_VERBOSITY_DEBUG, + "xine-lib:video_out_xshm:xshm_overlay_blend: Cannot blend bpp:%i\n", this->bpp); + /* it should never get here, unless a user tries to play in bpp:8 */ + break; + } + } + } +} + +static void clean_output_area (xshm_driver_t *this, xshm_frame_t *frame) { + int i; + xcb_rectangle_t rects[4]; + int rects_count = 0; + + memcpy( this->sc.border, frame->sc.border, sizeof(this->sc.border) ); + + pthread_mutex_lock(&this->main_mutex); + + for( i = 0; i < 4; i++ ) { + if( this->sc.border[i].w && this->sc.border[i].h ) + rects[rects_count].x = this->sc.border[i].x; + rects[rects_count].y = this->sc.border[i].y; + rects[rects_count].width = this->sc.border[i].w; + rects[rects_count].height = this->sc.border[i].h; + rects_count++; + } + + if (rects_count > 0) + xcb_poly_fill_rectangle(this->connection, this->window, this->gc, rects_count, rects); + + if (this->xoverlay) { + xcbosd_resize(this->xoverlay, this->sc.gui_width, this->sc.gui_height); + this->ovl_changed = 1; + } + + pthread_mutex_unlock(&this->main_mutex); +} + +static int xshm_redraw_needed (vo_driver_t *this_gen) { + xshm_driver_t *this = (xshm_driver_t *) this_gen; + int ret = 0; + + if( this->cur_frame ) { + this->sc.delivered_height = this->cur_frame->sc.delivered_height; + this->sc.delivered_width = this->cur_frame->sc.delivered_width; + this->sc.video_pixel_aspect = this->cur_frame->sc.video_pixel_aspect; + if( _x_vo_scale_redraw_needed( &this->sc ) ) { + + clean_output_area (this, this->cur_frame); + ret = 1; + } + } + else + ret = 1; + + return ret; +} + +static void xshm_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) { + xshm_driver_t *this = (xshm_driver_t *) this_gen; + xshm_frame_t *frame = (xshm_frame_t *) frame_gen; + + lprintf ("display frame...\n"); + lprintf ("about to draw frame (%d) %d x %d...\n", + frame->vo_frame.id, + frame->sc.output_width, frame->sc.output_height); + + /* + * tell gui that we are about to display a frame, + * ask for offset + */ + + this->sc.delivered_height = frame->sc.delivered_height; + this->sc.delivered_width = frame->sc.delivered_width; + this->sc.video_pixel_aspect = frame->sc.video_pixel_aspect; + if( _x_vo_scale_redraw_needed( &this->sc ) ) { + + clean_output_area (this, frame); + } + + if (this->cur_frame) { + + if ( (this->cur_frame->sc.output_width != frame->sc.output_width) + || (this->cur_frame->sc.output_height != frame->sc.output_height) + || (this->cur_frame->sc.output_xoffset != frame->sc.output_xoffset) + || (this->cur_frame->sc.output_yoffset != frame->sc.output_yoffset) ) + clean_output_area (this, frame); + + this->cur_frame->vo_frame.free (&this->cur_frame->vo_frame); + } + + this->cur_frame = frame; + + pthread_mutex_lock(&this->main_mutex); + lprintf ("display locked...\n"); + + if (frame->shmseg) { + + lprintf ("put image (shm)\n"); + xcb_shm_put_image(this->connection, this->window, this->gc, this->cur_frame->sc.output_width, + this->cur_frame->sc.output_height, 0, 0, this->cur_frame->sc.output_width, + this->cur_frame->sc.output_height, this->cur_frame->sc.output_xoffset, + this->cur_frame->sc.output_yoffset, this->depth, XCB_IMAGE_FORMAT_Z_PIXMAP, + 0, this->cur_frame->shmseg, 0); + + } else { + + lprintf ("put image (plain/remote)\n"); + xcb_put_image(this->connection, XCB_IMAGE_FORMAT_Z_PIXMAP, this->window, this->gc, + frame->sc.output_width, frame->sc.output_height, frame->sc.output_xoffset, frame->sc.output_yoffset, + 0, this->depth, frame->bytes_per_line * frame->sc.output_height, frame->image); + + } + xcb_flush(this->connection); + pthread_mutex_unlock(&this->main_mutex); + + lprintf ("display frame done\n"); +} + +static int xshm_get_property (vo_driver_t *this_gen, int property) { + xshm_driver_t *this = (xshm_driver_t *) this_gen; + + switch (property) { + case VO_PROP_ASPECT_RATIO: + return this->sc.user_ratio; + case VO_PROP_MAX_NUM_FRAMES: + return 15; + case VO_PROP_BRIGHTNESS: + return this->yuv2rgb_brightness; + case VO_PROP_CONTRAST: + return this->yuv2rgb_contrast; + case VO_PROP_SATURATION: + return this->yuv2rgb_saturation; + case VO_PROP_WINDOW_WIDTH: + return this->sc.gui_width; + case VO_PROP_WINDOW_HEIGHT: + return this->sc.gui_height; + default: + xprintf(this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xshm: tried to get unsupported property %d\n", property); + } + + return 0; +} + +static int xshm_set_property (vo_driver_t *this_gen, + int property, int value) { + xshm_driver_t *this = (xshm_driver_t *) this_gen; + + if ( property == VO_PROP_ASPECT_RATIO) { + + if (value>=XINE_VO_ASPECT_NUM_RATIOS) + value = XINE_VO_ASPECT_AUTO; + this->sc.user_ratio = value; + xprintf(this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xshm: aspect ratio changed to %s\n", _x_vo_scale_aspect_ratio_name(value)); + + } else if (property == VO_PROP_BRIGHTNESS) { + + this->yuv2rgb_brightness = value; + this->yuv2rgb_factory->set_csc_levels (this->yuv2rgb_factory, + this->yuv2rgb_brightness, + this->yuv2rgb_contrast, + this->yuv2rgb_saturation); + + this->sc.force_redraw = 1; + + } else if (property == VO_PROP_CONTRAST) { + + this->yuv2rgb_contrast = value; + this->yuv2rgb_factory->set_csc_levels (this->yuv2rgb_factory, + this->yuv2rgb_brightness, + this->yuv2rgb_contrast, + this->yuv2rgb_saturation); + + this->sc.force_redraw = 1; + + } else if (property == VO_PROP_SATURATION) { + + this->yuv2rgb_saturation = value; + this->yuv2rgb_factory->set_csc_levels (this->yuv2rgb_factory, + this->yuv2rgb_brightness, + this->yuv2rgb_contrast, + this->yuv2rgb_saturation); + + this->sc.force_redraw = 1; + + } else { + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xshm: tried to set unsupported property %d\n", property); + } + + return value; +} + +static void xshm_get_property_min_max (vo_driver_t *this_gen, + int property, int *min, int *max) { + /* xshm_driver_t *this = (xshm_driver_t *) this_gen; */ + + if (property == VO_PROP_BRIGHTNESS) { + *min = -128; + *max = +127; + } else if (property == VO_PROP_CONTRAST) { + *min = 0; + *max = 255; + } else if (property == VO_PROP_SATURATION) { + *min = 0; + *max = 255; + } else { + *min = 0; + *max = 0; + } +} + +static int xshm_gui_data_exchange (vo_driver_t *this_gen, + int data_type, void *data) { + xshm_driver_t *this = (xshm_driver_t *) this_gen; + + switch (data_type) { +#ifndef XINE_DISABLE_DEPRECATED_FEATURES + case XINE_GUI_SEND_COMPLETION_EVENT: + break; +#endif + + case XINE_GUI_SEND_EXPOSE_EVENT: + + lprintf ("expose event\n"); + + if (this->cur_frame) { + xcb_expose_event_t *xev = (xcb_expose_event_t *) data; + + if (xev && xev->count == 0) { + int i; + xcb_rectangle_t rects[4]; + int rects_count = 0; + + pthread_mutex_lock(&this->main_mutex); + if (this->cur_frame->shmseg) + xcb_shm_put_image(this->connection, this->window, this->gc, this->cur_frame->sc.output_width, + this->cur_frame->sc.output_height, 0, 0, this->cur_frame->sc.output_width, + this->cur_frame->sc.output_height, this->cur_frame->sc.output_xoffset, + this->cur_frame->sc.output_yoffset, this->depth, XCB_IMAGE_FORMAT_Z_PIXMAP, + 0, this->cur_frame->shmseg, 0); + else + xcb_put_image(this->connection, XCB_IMAGE_FORMAT_Z_PIXMAP, this->window, this->gc, + this->cur_frame->sc.output_width, this->cur_frame->sc.output_height, + this->cur_frame->sc.output_xoffset, this->cur_frame->sc.output_yoffset, + 0, this->depth, this->cur_frame->bytes_per_line * this->cur_frame->sc.output_height, + this->cur_frame->image); + + for( i = 0; i < 4; i++ ) { + if( this->sc.border[i].w && this->sc.border[i].h ) + rects[rects_count].x = this->sc.border[i].x; + rects[rects_count].y = this->sc.border[i].y; + rects[rects_count].width = this->sc.border[i].w; + rects[rects_count].height = this->sc.border[i].h; + rects_count++; + } + + if (rects_count > 0) + xcb_poly_fill_rectangle(this->connection, this->window, this->gc, rects_count, rects); + + if(this->xoverlay) + xcbosd_expose(this->xoverlay); + + xcb_flush(this->connection); + pthread_mutex_unlock(&this->main_mutex); + } + } + break; + + case XINE_GUI_SEND_DRAWABLE_CHANGED: + this->window = (xcb_window_t) data; + + pthread_mutex_lock(&this->main_mutex); + xcb_free_gc(this->connection, this->gc); + this->gc = xcb_generate_id(this->connection); + xcb_create_gc(this->connection, this->gc, this->window, XCB_GC_FOREGROUND, &this->screen->black_pixel); + if(this->xoverlay) + xcbosd_drawable_changed(this->xoverlay, this->window); + this->ovl_changed = 1; + pthread_mutex_unlock(&this->main_mutex); + break; + + case XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO: + + if (this->cur_frame) { + x11_rectangle_t *rect = data; + int x1, y1, x2, y2; + + _x_vo_scale_translate_gui2video(&this->cur_frame->sc, + rect->x, rect->y, + &x1, &y1); + _x_vo_scale_translate_gui2video(&this->cur_frame->sc, + rect->x + rect->w, rect->y + rect->h, + &x2, &y2); + rect->x = x1; + rect->y = y1; + rect->w = x2-x1; + rect->h = y2-y1; + } + break; + + default: + return -1; + } + + return 0; +} + +static void xshm_dispose (vo_driver_t *this_gen) { + xshm_driver_t *this = (xshm_driver_t *) this_gen; + + if (this->cur_frame) + this->cur_frame->vo_frame.dispose (&this->cur_frame->vo_frame); + + this->yuv2rgb_factory->dispose (this->yuv2rgb_factory); + + pthread_mutex_lock(&this->main_mutex); + xcb_free_gc(this->connection, this->gc); + pthread_mutex_unlock(&this->main_mutex); + + if( this->xoverlay ) { + pthread_mutex_lock(&this->main_mutex); + xcbosd_destroy(this->xoverlay); + pthread_mutex_unlock(&this->main_mutex); + } + + pthread_mutex_destroy(&this->main_mutex); + + _x_alphablend_free(&this->alphablend_extra_data); + + free (this); +} + +static int ImlibPaletteLUTGet(xshm_driver_t *this) { + static const xcb_atom_t CARDINAL = 6; + + xcb_intern_atom_cookie_t atom_cookie; + xcb_intern_atom_reply_t *atom_reply; + + xcb_get_property_cookie_t prop_cookie; + xcb_get_property_reply_t *prop_reply; + + atom_cookie = xcb_intern_atom(this->connection, 0, sizeof("_IMLIB_COLORMAP"), "_IMLIB_COLORMAP"); + atom_reply = xcb_intern_atom_reply(this->connection, atom_cookie, NULL); + + if (atom_reply == NULL) + return 0; + + prop_cookie = xcb_get_property(this->connection, 0, this->window, atom_reply->atom, CARDINAL, 0, 0x7fffffff); + prop_reply = xcb_get_property_reply(this->connection, prop_cookie, NULL); + + free(atom_reply); + + if (prop_reply == NULL) + return 0; + + if (prop_reply->format == 8) { + unsigned int i; + unsigned long j; + int num_ret = xcb_get_property_value_length(prop_reply); + char *retval = xcb_get_property_value(prop_reply); + + j = 1 + retval[0]*4; + this->yuv2rgb_cmap = malloc(sizeof(uint8_t) * 32 * 32 * 32); + for (i = 0; i < 32 * 32 * 32 && j < num_ret; i++) + this->yuv2rgb_cmap[i] = retval[1+4*retval[j++]+3]; + + free(prop_reply); + return 1; + } + + free(prop_reply); + return 0; +} + + +static char *visual_class_name(xcb_visualtype_t *visual) { + + switch (visual->_class) { + case XCB_VISUAL_CLASS_STATIC_GRAY: + return "StaticGray"; + case XCB_VISUAL_CLASS_GRAY_SCALE: + return "GrayScale"; + case XCB_VISUAL_CLASS_STATIC_COLOR: + return "StaticColor"; + case XCB_VISUAL_CLASS_PSEUDO_COLOR: + return "PseudoColor"; + case XCB_VISUAL_CLASS_TRUE_COLOR: + return "TrueColor"; + case XCB_VISUAL_CLASS_DIRECT_COLOR: + return "DirectColor"; + default: + return "unknown visual class"; + } +} + +static vo_driver_t *xshm_open_plugin(video_driver_class_t *class_gen, const void *visual_gen) { + xshm_class_t *class = (xshm_class_t *) class_gen; + config_values_t *config = class->config; + xcb_visual_t *visual = (xcb_visual_t *) visual_gen; + xshm_driver_t *this; + xcb_visualtype_t *visualtype; + int mode; + int swapped; + int cpu_byte_order; + int image_byte_order; + + xcb_get_window_attributes_cookie_t window_attrs_cookie; + xcb_get_window_attributes_reply_t *window_attrs_reply; + + xcb_get_geometry_cookie_t geometry_cookie; + xcb_get_geometry_reply_t *geometry_reply; + + const xcb_query_extension_reply_t *query_extension_reply; + + this = (xshm_driver_t *) xine_xmalloc (sizeof (xshm_driver_t)); + + if (!this) + return NULL; + + pthread_mutex_init(&this->main_mutex, NULL); + + _x_alphablend_init(&this->alphablend_extra_data, class->xine); + + this->connection = visual->connection; + this->screen = visual->screen; + this->window = visual->window; + + _x_vo_scale_init( &this->sc, 0, 0, config ); + this->sc.frame_output_cb = visual->frame_output_cb; + this->sc.dest_size_cb = visual->dest_size_cb; + this->sc.user_data = visual->user_data; + + this->sc.user_ratio = XINE_VO_ASPECT_AUTO; + + this->cur_frame = NULL; + this->gc = xcb_generate_id(this->connection); + xcb_create_gc(this->connection, this->gc, this->window, XCB_GC_FOREGROUND, &this->screen->black_pixel); + this->xoverlay = NULL; + this->ovl_changed = 0; + + this->xine = class->xine; + + this->vo_driver.get_capabilities = xshm_get_capabilities; + this->vo_driver.alloc_frame = xshm_alloc_frame; + this->vo_driver.update_frame_format = xshm_update_frame_format; + this->vo_driver.overlay_begin = xshm_overlay_begin; + this->vo_driver.overlay_blend = xshm_overlay_blend; + this->vo_driver.overlay_end = xshm_overlay_end; + this->vo_driver.display_frame = xshm_display_frame; + this->vo_driver.get_property = xshm_get_property; + this->vo_driver.set_property = xshm_set_property; + this->vo_driver.get_property_min_max = xshm_get_property_min_max; + this->vo_driver.gui_data_exchange = xshm_gui_data_exchange; + this->vo_driver.dispose = xshm_dispose; + this->vo_driver.redraw_needed = xshm_redraw_needed; + + /* + * + * depth in X11 terminology land is the number of bits used to + * actually represent the colour. + * + * bpp in X11 land means how many bits in the frame buffer per + * pixel. + * + * ex. 15 bit color is 15 bit depth and 16 bpp. Also 24 bit + * color is 24 bit depth, but can be 24 bpp or 32 bpp. + */ + + window_attrs_cookie = xcb_get_window_attributes(this->connection, this->window); + geometry_cookie = xcb_get_geometry(this->connection, this->window); + xcb_prefetch_extension_data(this->connection, &xcb_shm_id); + + window_attrs_reply = xcb_get_window_attributes_reply(this->connection, window_attrs_cookie, NULL); + + visualtype = NULL; + { + xcb_depth_t *depth = xcb_screen_allowed_depths_iterator(this->screen).data; + xcb_visualtype_t *vis = xcb_depth_visuals(depth); + xcb_visualtype_t *vis_end = vis + xcb_depth_visuals_length(depth); + + for (; vis != vis_end; ++vis) + if (window_attrs_reply->visual == vis->visual_id) { + visualtype = vis; + break; + } + } + + free(window_attrs_reply); + + geometry_reply = xcb_get_geometry_reply(this->connection, geometry_cookie, NULL); + + this->depth = geometry_reply->depth; + + free(geometry_reply); + + if (this->depth>16) + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("\n\nWARNING: current display depth is %d. For better performance\n" + "a depth of 16 bpp is recommended!\n\n"), this->depth); + + /* + * check for X shared memory support + */ + + query_extension_reply = xcb_get_extension_data(this->connection, &xcb_shm_id); + if (query_extension_reply && query_extension_reply->present) { + this->use_shm = 1; + } + else { + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("video_out_xshm: MIT shared memory extension not present on display.\n")); + this->use_shm = 0; + } + + { + const xcb_setup_t *setup = xcb_get_setup(this->connection); + xcb_format_t *fmt = xcb_setup_pixmap_formats(setup); + xcb_format_t *fmt_end = fmt + xcb_setup_pixmap_formats_length(setup); + + for (; fmt != fmt_end; ++fmt) + if(fmt->depth == this->depth) { + this->bpp = fmt->bits_per_pixel; + this->scanline_pad = fmt->scanline_pad; + break; + } + + if (fmt == fmt_end) { + if (this->depth <= 4) + this->bpp = 4; + else if (this->depth <= 8) + this->bpp = 8; + else if (this->depth <= 16) + this->bpp = 16; + else + this->bpp = 32; + this->scanline_pad = setup->bitmap_format_scanline_pad; + } + + image_byte_order = setup->image_byte_order; + } + + /* + * Is the same byte order in use on the X11 client and server? + */ + cpu_byte_order = htonl(1) == 1 ? XCB_IMAGE_ORDER_MSB_FIRST : XCB_IMAGE_ORDER_LSB_FIRST; + swapped = cpu_byte_order != image_byte_order; + + xprintf(this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xshm: video mode depth is %d (%d bpp), %s, %sswapped,\n" + "\tred: %08x, green: %08x, blue: %08x\n", + this->depth, this->bpp, + visual_class_name(visualtype), + swapped ? "" : "not ", + visualtype->red_mask, visualtype->green_mask, visualtype->blue_mask); + + mode = 0; + + switch (visualtype->_class) { + case XCB_VISUAL_CLASS_TRUE_COLOR: + switch (this->depth) { + case 24: + case 32: + if (this->bpp == 32) { + if (visualtype->red_mask == 0x00ff0000) + mode = MODE_32_RGB; + else + mode = MODE_32_BGR; + } else { + if (visualtype->red_mask == 0x00ff0000) + mode = MODE_24_RGB; + else + mode = MODE_24_BGR; + } + break; + case 16: + if (visualtype->red_mask == 0xf800) + mode = MODE_16_RGB; + else + mode = MODE_16_BGR; + break; + case 15: + if (visualtype->red_mask == 0x7C00) + mode = MODE_15_RGB; + else + mode = MODE_15_BGR; + break; + case 8: + if (visualtype->red_mask == 0xE0) + mode = MODE_8_RGB; /* Solaris x86: RGB332 */ + else + mode = MODE_8_BGR; /* XFree86: BGR233 */ + break; + } + break; + + case XCB_VISUAL_CLASS_STATIC_GRAY: + if (this->depth == 8) + mode = MODE_8_GRAY; + break; + + case XCB_VISUAL_CLASS_PSEUDO_COLOR: + case XCB_VISUAL_CLASS_GRAY_SCALE: + if (this->depth <= 8 && ImlibPaletteLUTGet(this)) + mode = MODE_PALETTE; + break; + } + + if (!mode) { + xprintf (this->xine, XINE_VERBOSITY_LOG, + _("video_out_xshm: your video mode was not recognized, sorry :-(\n")); + return NULL; + } + + this->yuv2rgb_brightness = 0; + this->yuv2rgb_contrast = 128; + this->yuv2rgb_saturation = 128; + + this->yuv2rgb_factory = yuv2rgb_factory_init (mode, swapped, + this->yuv2rgb_cmap); + this->yuv2rgb_factory->set_csc_levels (this->yuv2rgb_factory, + this->yuv2rgb_brightness, + this->yuv2rgb_contrast, + this->yuv2rgb_saturation); + + this->xoverlay = xcbosd_create(this->xine, this->connection, this->screen, + this->window, XCBOSD_SHAPED); + + return &this->vo_driver; +} + +/* + * class functions + */ + +static char* xshm_get_identifier (video_driver_class_t *this_gen) { + return "XShm"; +} + +static char* xshm_get_description (video_driver_class_t *this_gen) { + return _("xine video output plugin using the MIT X shared memory extension"); +} + +static void xshm_dispose_class (video_driver_class_t *this_gen) { + xshm_class_t *this = (xshm_class_t *) this_gen; + + free (this); +} + +static void *xshm_init_class (xine_t *xine, void *visual_gen) { + xshm_class_t *this = (xshm_class_t *) xine_xmalloc (sizeof (xshm_class_t)); + + this->driver_class.open_plugin = xshm_open_plugin; + this->driver_class.get_identifier = xshm_get_identifier; + this->driver_class.get_description = xshm_get_description; + this->driver_class.dispose = xshm_dispose_class; + this->config = xine->config; + this->xine = xine; + + return this; +} + + +static const vo_info_t vo_info_xshm = { + 6, /* priority */ + XINE_VISUAL_TYPE_XCB /* visual type */ +}; + + +/* + * exported plugin catalog entry + */ + +const plugin_info_t xine_plugin_info[] EXPORTED = { + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_VIDEO_OUT, 21, "xshm", XINE_VERSION_CODE, &vo_info_xshm, xshm_init_class }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; Index: src/video_out/video_out_xcbxv.c =================================================================== RCS file: src/video_out/video_out_xcbxv.c diff -N src/video_out/video_out_xcbxv.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/video_out/video_out_xcbxv.c 7 Feb 2007 02:41:40 -0000 @@ -0,0 +1,1598 @@ +/* + * Copyright (C) 2000-2004, 2007 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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: xine-lib-1.1.4-xcb.patch,v 1.1 2007-05-08 20:43:46 niro Exp $ + * + * video_out_xcbxv.c, X11 video extension interface for xine + * + * based on mpeg2dec code from + * Aaron Holtzman + * + * Xv image support by Gerd Knorr + * + * xine-specific code by Guenter Bartsch + * + * overlay support by James Courtier-Dutton - July 2001 + * X11 unscaled overlay support by Miguel Freitas - Nov 2003 + * ported to xcb by Christoph Pfister - Feb 2007 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_XV + +#include +#include +#include +#include +#include + +#include +#if defined(__FreeBSD__) +#include +#endif +#include +#include +#include + +#include + +#define LOG_MODULE "video_out_xcbxv" +#define LOG_VERBOSE +/* +#define LOG +*/ + +#include "xine.h" +#include "video_out.h" +#include "xine_internal.h" +/* #include "overlay.h" */ +#include "deinterlace.h" +#include "xineutils.h" +#include "vo_scale.h" +#include "xcbosd.h" + +typedef struct xv_driver_s xv_driver_t; + +typedef struct { + int value; + int min; + int max; + xcb_atom_t atom; + + cfg_entry_t *entry; + + xv_driver_t *this; +} xv_property_t; + +typedef struct { + char *name; + int value; +} xv_portattribute_t; + +typedef struct { + vo_frame_t vo_frame; + + int width, height, format; + double ratio; + + uint8_t *image; + xcb_shm_seg_t shmseg; + unsigned int xv_format; + unsigned int xv_data_size; + unsigned int xv_width; + unsigned int xv_height; + unsigned int xv_pitches[3]; + unsigned int xv_offsets[3]; + +} xv_frame_t; + + +struct xv_driver_s { + + vo_driver_t vo_driver; + + config_values_t *config; + + /* xcb / xv related stuff */ + xcb_connection_t *connection; + xcb_screen_t *screen; + xcb_window_t window; + unsigned int xv_format_yv12; + unsigned int xv_format_yuy2; + xcb_gc_t gc; + xcb_xv_port_t xv_port; + + int use_shm; + int use_pitch_alignment; + xv_property_t props[VO_NUM_PROPERTIES]; + uint32_t capabilities; + + xv_frame_t *recent_frames[VO_NUM_RECENT_FRAMES]; + xv_frame_t *cur_frame; + xcbosd *xoverlay; + int ovl_changed; + + /* all scaling information goes here */ + vo_scale_t sc; + + xv_frame_t deinterlace_frame; + int deinterlace_method; + int deinterlace_enabled; + + int use_colorkey; + uint32_t colorkey; + + /* hold initial port attributes values to restore on exit */ + xine_list_t *port_attributes; + + xine_t *xine; + + alphablend_t alphablend_extra_data; + + pthread_mutex_t main_mutex; + +}; + +typedef struct { + video_driver_class_t driver_class; + + config_values_t *config; + xine_t *xine; +} xv_class_t; + +static uint32_t xv_get_capabilities (vo_driver_t *this_gen) { + xv_driver_t *this = (xv_driver_t *) this_gen; + + return this->capabilities; +} + +static void xv_frame_field (vo_frame_t *vo_img, int which_field) { + /* not needed for Xv */ +} + +static void xv_frame_dispose (vo_frame_t *vo_img) { + xv_frame_t *frame = (xv_frame_t *) vo_img ; + xv_driver_t *this = (xv_driver_t *) vo_img->driver; + + if (frame->shmseg) { + pthread_mutex_lock(&this->main_mutex); + xcb_shm_detach(this->connection, frame->shmseg); + frame->shmseg = 0; + pthread_mutex_unlock(&this->main_mutex); + shmdt(frame->image); + } + else + free(frame->image); + + free (frame); +} + +static vo_frame_t *xv_alloc_frame (vo_driver_t *this_gen) { + /* xv_driver_t *this = (xv_driver_t *) this_gen; */ + xv_frame_t *frame ; + + frame = (xv_frame_t *) xine_xmalloc (sizeof (xv_frame_t)); + if (!frame) + return NULL; + + pthread_mutex_init (&frame->vo_frame.mutex, NULL); + + /* + * supply required functions + */ + frame->vo_frame.proc_slice = NULL; + frame->vo_frame.proc_frame = NULL; + frame->vo_frame.field = xv_frame_field; + frame->vo_frame.dispose = xv_frame_dispose; + frame->vo_frame.driver = this_gen; + + return (vo_frame_t *) frame; +} + +static void create_ximage(xv_driver_t *this, xv_frame_t *frame, int width, int height, int format) +{ + xcb_xv_query_image_attributes_cookie_t query_attributes_cookie; + xcb_xv_query_image_attributes_reply_t *query_attributes_reply; + + unsigned int length; + + if (this->use_pitch_alignment) { + width = (width + 7) & ~0x7; + } + + switch (format) { + case XINE_IMGFMT_YV12: + frame->xv_format = this->xv_format_yv12; + break; + case XINE_IMGFMT_YUY2: + frame->xv_format = this->xv_format_yuy2; + break; + default: + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "create_ximage: unknown format %08x\n",format); + _x_abort(); + } + + query_attributes_cookie = xcb_xv_query_image_attributes(this->connection, this->xv_port, frame->xv_format, width, height); + query_attributes_reply = xcb_xv_query_image_attributes_reply(this->connection, query_attributes_cookie, NULL); + + if (query_attributes_reply == NULL) + return; + + frame->xv_data_size = query_attributes_reply->data_size; + frame->xv_width = query_attributes_reply->width; + frame->xv_height = query_attributes_reply->height; + + length = xcb_xv_query_image_attributes_pitches_length(query_attributes_reply); + if (length > 3) + length = 3; + memcpy(frame->xv_pitches, xcb_xv_query_image_attributes_pitches(query_attributes_reply), length * sizeof(frame->xv_pitches[0])); + + length = xcb_xv_query_image_attributes_offsets_length(query_attributes_reply); + if (length > 3) + length = 3; + memcpy(frame->xv_offsets, xcb_xv_query_image_attributes_offsets(query_attributes_reply), length * sizeof(frame->xv_offsets[0])); + + free(query_attributes_reply); + + if (this->use_shm) { + int shmid; + xcb_void_cookie_t shm_attach_cookie; + xcb_generic_error_t *generic_error; + + /* + * try shm + */ + + if (frame->xv_data_size == 0) { + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("video_out_xv: XvShmCreateImage returned a zero size\n" + "video_out_xv: => not using MIT Shared Memory extension.\n")); + goto shm_fail1; + } + + shmid = shmget(IPC_PRIVATE, frame->xv_data_size, IPC_CREAT | 0777); + + if (shmid < 0 ) { + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("video_out_xv: shared memory error in shmget: %s\n" + "video_out_xv: => not using MIT Shared Memory extension.\n"), strerror(errno)); + goto shm_fail1; + } + + frame->image = shmat(shmid, 0, 0); + + if (frame->image == ((void *) -1)) { + xprintf(this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xv: shared memory error (address error)\n"); + goto shm_fail2; + } + + frame->shmseg = xcb_generate_id(this->connection); + shm_attach_cookie = xcb_shm_attach_checked(this->connection, frame->shmseg, shmid, 0); + generic_error = xcb_request_check(this->connection, shm_attach_cookie); + + if (generic_error != NULL) { + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("video_out_xv: x11 error during shared memory XImage creation\n" + "video_out_xv: => not using MIT Shared Memory extension.\n")); + free(generic_error); + goto shm_fail3; + } + + /* + * Now that the Xserver has learned about and attached to the + * shared memory segment, delete it. It's actually deleted by + * the kernel when all users of that segment have detached from + * it. Gives an automatic shared memory cleanup in case we crash. + */ + + shmctl(shmid, IPC_RMID, 0); + + return; + + shm_fail3: + frame->shmseg = 0; + shmdt(frame->image); + shm_fail2: + shmctl(shmid, IPC_RMID, 0); + shm_fail1: + this->use_shm = 0; + } + + /* + * fall back to plain Xv if necessary + */ + + switch (format) { + case XINE_IMGFMT_YV12: + frame->image = malloc(width * height * 3/2); + break; + case XINE_IMGFMT_YUY2: + frame->image = malloc(width * height * 2); + break; + default: + xprintf (this->xine, XINE_VERBOSITY_DEBUG, "create_ximage: unknown format %08x\n",format); + _x_abort(); + } +} + +static void dispose_ximage(xv_driver_t *this, xv_frame_t *frame) +{ + if (frame->shmseg) { + xcb_shm_detach(this->connection, frame->shmseg); + frame->shmseg = 0; + shmdt(frame->image); + } else + free(frame->image); + frame->image = NULL; +} + +static void xv_update_frame_format (vo_driver_t *this_gen, + vo_frame_t *frame_gen, + uint32_t width, uint32_t height, + double ratio, int format, int flags) { + xv_driver_t *this = (xv_driver_t *) this_gen; + xv_frame_t *frame = (xv_frame_t *) frame_gen; + + if (this->use_pitch_alignment) { + width = (width + 7) & ~0x7; + } + + if ((frame->width != width) + || (frame->height != height) + || (frame->format != format)) { + + /* printf ("video_out_xv: updating frame to %d x %d (ratio=%d, format=%08x)\n",width,height,ratio_code,format); */ + + pthread_mutex_lock(&this->main_mutex); + + /* + * (re-) allocate xvimage + */ + + if (frame->image) + dispose_ximage(this, frame); + + create_ximage(this, frame, width, height, format); + + if(format == XINE_IMGFMT_YUY2) { + frame->vo_frame.pitches[0] = frame->xv_pitches[0]; + frame->vo_frame.base[0] = frame->image + frame->xv_offsets[0]; + } + else { + frame->vo_frame.pitches[0] = frame->xv_pitches[0]; + frame->vo_frame.pitches[1] = frame->xv_pitches[2]; + frame->vo_frame.pitches[2] = frame->xv_pitches[1]; + frame->vo_frame.base[0] = frame->image + frame->xv_offsets[0]; + frame->vo_frame.base[1] = frame->image + frame->xv_offsets[2]; + frame->vo_frame.base[2] = frame->image + frame->xv_offsets[1]; + } + + frame->width = width; + frame->height = height; + frame->format = format; + + pthread_mutex_unlock(&this->main_mutex); + } + + frame->ratio = ratio; +} + +#define DEINTERLACE_CROMA +static void xv_deinterlace_frame (xv_driver_t *this) { + uint8_t *recent_bitmaps[VO_NUM_RECENT_FRAMES]; + xv_frame_t *frame = this->recent_frames[0]; + int i; + int xvscaling; + + xvscaling = (this->deinterlace_method == DEINTERLACE_ONEFIELDXV) ? 2 : 1; + + if (!this->deinterlace_frame.image + || (frame->width != this->deinterlace_frame.width) + || (frame->height != this->deinterlace_frame.height ) + || (frame->format != this->deinterlace_frame.format) + || (frame->ratio != this->deinterlace_frame.ratio)) { + pthread_mutex_lock(&this->main_mutex); + + if(this->deinterlace_frame.image) + dispose_ximage(this, &this->deinterlace_frame); + + create_ximage(this, &this->deinterlace_frame, frame->width, frame->height / xvscaling, frame->format); + this->deinterlace_frame.width = frame->width; + this->deinterlace_frame.height = frame->height; + this->deinterlace_frame.format = frame->format; + this->deinterlace_frame.ratio = frame->ratio; + + pthread_mutex_unlock(&this->main_mutex); + } + + + if ( this->deinterlace_method != DEINTERLACE_ONEFIELDXV ) { +#ifdef DEINTERLACE_CROMA + + /* I don't think this is the right way to do it (deinterlacing croma by croma info). + DScaler deinterlaces croma together with luma, but it's easier for them because + they have that components 1:1 at the same table. + */ + for( i = 0; i < VO_NUM_RECENT_FRAMES; i++ ) + if( this->recent_frames[i] && this->recent_frames[i]->width == frame->width && + this->recent_frames[i]->height == frame->height ) + recent_bitmaps[i] = this->recent_frames[i]->image + frame->width*frame->height; + else + recent_bitmaps[i] = NULL; + + deinterlace_yuv( this->deinterlace_frame.image+frame->width*frame->height, + recent_bitmaps, frame->width/2, frame->height/2, this->deinterlace_method ); + for( i = 0; i < VO_NUM_RECENT_FRAMES; i++ ) + if( this->recent_frames[i] && this->recent_frames[i]->width == frame->width && + this->recent_frames[i]->height == frame->height ) + recent_bitmaps[i] = this->recent_frames[i]->image + frame->width*frame->height*5/4; + else + recent_bitmaps[i] = NULL; + + deinterlace_yuv( this->deinterlace_frame.image+frame->width*frame->height*5/4, + recent_bitmaps, frame->width/2, frame->height/2, this->deinterlace_method ); + +#else + + /* know bug: we are not deinterlacing Cb and Cr */ + xine_fast_memcpy(this->deinterlace_frame.image + frame->width*frame->height, + frame->image + frame->width*frame->height, + frame->width*frame->height*1/2); + +#endif + + for( i = 0; i < VO_NUM_RECENT_FRAMES; i++ ) + if( this->recent_frames[i] && this->recent_frames[i]->width == frame->width && + this->recent_frames[i]->height == frame->height ) + recent_bitmaps[i] = this->recent_frames[i]->image; + else + recent_bitmaps[i] = NULL; + + deinterlace_yuv( this->deinterlace_frame.image, recent_bitmaps, + frame->width, frame->height, this->deinterlace_method ); + } + else { + /* + dirty and cheap deinterlace method: we give half of the lines to xv + driver and let it scale for us. + note that memcpy's below don't seem to impact much on performance, + specially when fast memcpys are available. + */ + uint8_t *dst, *src; + + dst = this->deinterlace_frame.image; + src = this->recent_frames[0]->image; + for( i = 0; i < frame->height; i+=2 ) { + xine_fast_memcpy(dst,src,frame->width); + dst += frame->width; + src += 2 * frame->width; + } + + dst = this->deinterlace_frame.image + frame->width * frame->height / 2; + src = this->recent_frames[0]->image + frame->width * frame->height; + for( i = 0; i < frame->height; i+=4 ) { + xine_fast_memcpy(dst,src,frame->width / 2); + dst += frame->width / 2; + src += frame->width; + } + + dst = this->deinterlace_frame.image + frame->width * frame->height * 5 / 8; + src = this->recent_frames[0]->image + frame->width * frame->height * 5 / 4; + for( i = 0; i < frame->height; i+=4 ) { + xine_fast_memcpy(dst,src,frame->width / 2); + dst += frame->width / 2; + src += frame->width; + } + } + + this->cur_frame = &this->deinterlace_frame; +} + +static void xv_clean_output_area (xv_driver_t *this) { + int i; + xcb_rectangle_t rects[4]; + int rects_count = 0; + + pthread_mutex_lock(&this->main_mutex); + + xcb_change_gc(this->connection, this->gc, XCB_GC_FOREGROUND, &this->screen->black_pixel); + + for( i = 0; i < 4; i++ ) { + if( this->sc.border[i].w && this->sc.border[i].h ) { + rects[rects_count].x = this->sc.border[i].x; + rects[rects_count].y = this->sc.border[i].y; + rects[rects_count].width = this->sc.border[i].w; + rects[rects_count].height = this->sc.border[i].h; + rects_count++; + } + } + + if (rects_count > 0) + xcb_poly_fill_rectangle(this->connection, this->window, this->gc, rects_count, rects); + + if (this->use_colorkey) { + xcb_change_gc(this->connection, this->gc, XCB_GC_FOREGROUND, &this->colorkey); + xcb_rectangle_t rectangle = { this->sc.output_xoffset, this->sc.output_yoffset, + this->sc.output_width, this->sc.output_height }; + xcb_poly_fill_rectangle(this->connection, this->window, this->gc, 1, &rectangle); + } + + if (this->xoverlay) { + xcbosd_resize(this->xoverlay, this->sc.gui_width, this->sc.gui_height); + this->ovl_changed = 1; + } + + pthread_mutex_unlock(&this->main_mutex); +} + +/* + * convert delivered height/width to ideal width/height + * taking into account aspect ratio and zoom factor + */ + +static void xv_compute_ideal_size (xv_driver_t *this) { + _x_vo_scale_compute_ideal_size( &this->sc ); +} + + +/* + * make ideal width/height "fit" into the gui + */ + +static void xv_compute_output_size (xv_driver_t *this) { + + _x_vo_scale_compute_output_size( &this->sc ); + + /* onefield_xv divide by 2 the number of lines */ + if (this->deinterlace_enabled + && (this->deinterlace_method == DEINTERLACE_ONEFIELDXV) + && this->cur_frame && (this->cur_frame->format == XINE_IMGFMT_YV12)) { + this->sc.displayed_height = this->sc.displayed_height / 2 - 1; + this->sc.displayed_yoffset = this->sc.displayed_yoffset / 2; + } +} + +static void xv_overlay_begin (vo_driver_t *this_gen, + vo_frame_t *frame_gen, int changed) { + xv_driver_t *this = (xv_driver_t *) this_gen; + + this->ovl_changed += changed; + + if( this->ovl_changed && this->xoverlay ) { + pthread_mutex_lock(&this->main_mutex); + xcbosd_clear(this->xoverlay); + pthread_mutex_unlock(&this->main_mutex); + } + + this->alphablend_extra_data.offset_x = frame_gen->overlay_offset_x; + this->alphablend_extra_data.offset_y = frame_gen->overlay_offset_y; +} + +static void xv_overlay_end (vo_driver_t *this_gen, vo_frame_t *vo_img) { + xv_driver_t *this = (xv_driver_t *) this_gen; + + if( this->ovl_changed && this->xoverlay ) { + pthread_mutex_lock(&this->main_mutex); + xcbosd_expose(this->xoverlay); + pthread_mutex_unlock(&this->main_mutex); + } + + this->ovl_changed = 0; +} + +static void xv_overlay_blend (vo_driver_t *this_gen, + vo_frame_t *frame_gen, vo_overlay_t *overlay) { + xv_driver_t *this = (xv_driver_t *) this_gen; + xv_frame_t *frame = (xv_frame_t *) frame_gen; + + if (overlay->rle) { + if( overlay->unscaled ) { + if( this->ovl_changed && this->xoverlay ) { + pthread_mutex_lock(&this->main_mutex); + xcbosd_blend(this->xoverlay, overlay); + pthread_mutex_unlock(&this->main_mutex); + } + } else { + if (frame->format == XINE_IMGFMT_YV12) + _x_blend_yuv(frame->vo_frame.base, overlay, + frame->width, frame->height, frame->vo_frame.pitches, + &this->alphablend_extra_data); + else + _x_blend_yuy2(frame->vo_frame.base[0], overlay, + frame->width, frame->height, frame->vo_frame.pitches[0], + &this->alphablend_extra_data); + } + } +} + +static void xv_add_recent_frame (xv_driver_t *this, xv_frame_t *frame) { + int i; + + i = VO_NUM_RECENT_FRAMES-1; + if( this->recent_frames[i] ) + this->recent_frames[i]->vo_frame.free + (&this->recent_frames[i]->vo_frame); + + for( ; i ; i-- ) + this->recent_frames[i] = this->recent_frames[i-1]; + + this->recent_frames[0] = frame; +} + +/* currently not used - we could have a method to call this from video loop */ +#if 0 +static void xv_flush_recent_frames (xv_driver_t *this) { + int i; + + for( i=0; i < VO_NUM_RECENT_FRAMES; i++ ) { + if( this->recent_frames[i] ) + this->recent_frames[i]->vo_frame.free + (&this->recent_frames[i]->vo_frame); + this->recent_frames[i] = NULL; + } +} +#endif + +static int xv_redraw_needed (vo_driver_t *this_gen) { + xv_driver_t *this = (xv_driver_t *) this_gen; + int ret = 0; + + if( this->cur_frame ) { + + this->sc.delivered_height = this->cur_frame->height; + this->sc.delivered_width = this->cur_frame->width; + this->sc.delivered_ratio = this->cur_frame->ratio; + + this->sc.crop_left = this->cur_frame->vo_frame.crop_left; + this->sc.crop_right = this->cur_frame->vo_frame.crop_right; + this->sc.crop_top = this->cur_frame->vo_frame.crop_top; + this->sc.crop_bottom = this->cur_frame->vo_frame.crop_bottom; + + xv_compute_ideal_size(this); + + if( _x_vo_scale_redraw_needed( &this->sc ) ) { + + xv_compute_output_size (this); + + xv_clean_output_area (this); + + ret = 1; + } + } + else + ret = 1; + + return ret; +} + +static void xv_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen) { + xv_driver_t *this = (xv_driver_t *) this_gen; + xv_frame_t *frame = (xv_frame_t *) frame_gen; + /* + printf ("video_out_xv: xv_display_frame...\n"); + */ + + /* + * queue frames (deinterlacing) + * free old frames + */ + + xv_add_recent_frame (this, frame); /* deinterlacing */ + + this->cur_frame = frame; + + /* + * let's see if this frame is different in size / aspect + * ratio from the previous one + */ + if ( (frame->width != this->sc.delivered_width) + || (frame->height != this->sc.delivered_height) + || (frame->ratio != this->sc.delivered_ratio) ) { + lprintf("frame format changed\n"); + this->sc.force_redraw = 1; /* trigger re-calc of output size */ + } + + /* + * deinterlace frame if necessary + * (currently only working for YUV images) + */ + + if (this->deinterlace_enabled && this->deinterlace_method + && frame->format == XINE_IMGFMT_YV12 + && (deinterlace_yuv_supported( this->deinterlace_method ) == 1 + || this->deinterlace_method == DEINTERLACE_ONEFIELDXV)) + xv_deinterlace_frame (this); + + /* + * tell gui that we are about to display a frame, + * ask for offset and output size + */ + xv_redraw_needed (this_gen); + + pthread_mutex_lock(&this->main_mutex); + + if (this->cur_frame->shmseg) { + xcb_xv_shm_put_image(this->connection, this->xv_port, this->window, this->gc, + this->cur_frame->shmseg, this->cur_frame->xv_format, 0, + 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_frame->xv_width, this->cur_frame->xv_height, 0); + + } else { + xcb_xv_put_image(this->connection, this->xv_port, this->window, this->gc, + this->cur_frame->xv_format, + 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_frame->xv_width, this->cur_frame->xv_height, + this->cur_frame->xv_data_size, this->cur_frame->image); + } + + xcb_flush(this->connection); + + pthread_mutex_unlock(&this->main_mutex); + + /* + printf ("video_out_xv: xv_display_frame... done\n"); + */ +} + +static int xv_get_property (vo_driver_t *this_gen, int property) { + xv_driver_t *this = (xv_driver_t *) this_gen; + + switch (property) { + case VO_PROP_WINDOW_WIDTH: + this->props[property].value = this->sc.gui_width; + break; + case VO_PROP_WINDOW_HEIGHT: + this->props[property].value = this->sc.gui_height; + break; + } + + lprintf("video_out_xv: property #%d = %d\n", property, this->props[property].value); + + return this->props[property].value; +} + +static void xv_property_callback (void *property_gen, xine_cfg_entry_t *entry) { + xv_property_t *property = (xv_property_t *) property_gen; + xv_driver_t *this = property->this; + + pthread_mutex_lock(&this->main_mutex); + xcb_xv_set_port_attribute(this->connection, this->xv_port, + property->atom, entry->num_value); + pthread_mutex_unlock(&this->main_mutex); +} + +static int xv_set_property (vo_driver_t *this_gen, + int property, int value) { + xv_driver_t *this = (xv_driver_t *) this_gen; + + if (this->props[property].atom != XCB_NONE) { + xcb_xv_get_port_attribute_cookie_t get_attribute_cookie; + xcb_xv_get_port_attribute_reply_t *get_attribute_reply; + + /* value is out of bound */ + if((value < this->props[property].min) || (value > this->props[property].max)) + value = (this->props[property].min + this->props[property].max) >> 1; + + pthread_mutex_lock(&this->main_mutex); + xcb_xv_set_port_attribute(this->connection, this->xv_port, + this->props[property].atom, value); + + get_attribute_cookie = xcb_xv_get_port_attribute(this->connection, this->xv_port, this->props[property].atom); + get_attribute_reply = xcb_xv_get_port_attribute_reply(this->connection, get_attribute_cookie, NULL); + this->props[property].value = get_attribute_reply->value; + free(get_attribute_reply); + + pthread_mutex_unlock(&this->main_mutex); + + if (this->props[property].entry) + this->props[property].entry->num_value = this->props[property].value; + + return this->props[property].value; + } + else { + switch (property) { + + case VO_PROP_INTERLACED: + this->props[property].value = value; + xprintf(this->xine, XINE_VERBOSITY_LOG, + "video_out_xv: VO_PROP_INTERLACED(%d)\n", this->props[property].value); + this->deinterlace_enabled = value; + if (this->deinterlace_method == DEINTERLACE_ONEFIELDXV) { + xv_compute_ideal_size (this); + xv_compute_output_size (this); + } + break; + + case VO_PROP_ASPECT_RATIO: + if (value>=XINE_VO_ASPECT_NUM_RATIOS) + value = XINE_VO_ASPECT_AUTO; + + this->props[property].value = value; + xprintf(this->xine, XINE_VERBOSITY_LOG, + "video_out_xv: VO_PROP_ASPECT_RATIO(%d)\n", this->props[property].value); + this->sc.user_ratio = value; + + xv_compute_ideal_size (this); + + this->sc.force_redraw = 1; /* trigger re-calc of output size */ + break; + + case VO_PROP_ZOOM_X: + if ((value >= XINE_VO_ZOOM_MIN) && (value <= XINE_VO_ZOOM_MAX)) { + this->props[property].value = value; + xprintf(this->xine, XINE_VERBOSITY_LOG, + "video_out_xv: VO_PROP_ZOOM_X = %d\n", this->props[property].value); + + this->sc.zoom_factor_x = (double)value / (double)XINE_VO_ZOOM_STEP; + + xv_compute_ideal_size (this); + + this->sc.force_redraw = 1; /* trigger re-calc of output size */ + } + break; + + case VO_PROP_ZOOM_Y: + if ((value >= XINE_VO_ZOOM_MIN) && (value <= XINE_VO_ZOOM_MAX)) { + this->props[property].value = value; + xprintf(this->xine, XINE_VERBOSITY_LOG, + "video_out_xv: VO_PROP_ZOOM_Y = %d\n", this->props[property].value); + + this->sc.zoom_factor_y = (double)value / (double)XINE_VO_ZOOM_STEP; + + xv_compute_ideal_size (this); + + this->sc.force_redraw = 1; /* trigger re-calc of output size */ + } + break; + } + } + + return value; +} + +static void xv_get_property_min_max (vo_driver_t *this_gen, + int property, int *min, int *max) { + xv_driver_t *this = (xv_driver_t *) this_gen; + + *min = this->props[property].min; + *max = this->props[property].max; +} + +static int xv_gui_data_exchange (vo_driver_t *this_gen, + int data_type, void *data) { + xv_driver_t *this = (xv_driver_t *) this_gen; + + switch (data_type) { +#ifndef XINE_DISABLE_DEPRECATED_FEATURES + case XINE_GUI_SEND_COMPLETION_EVENT: + break; +#endif + + case XINE_GUI_SEND_EXPOSE_EVENT: { + /* XExposeEvent * xev = (XExposeEvent *) data; */ + + if (this->cur_frame) { + + pthread_mutex_lock(&this->main_mutex); + + if (this->cur_frame->shmseg) { + xcb_xv_shm_put_image(this->connection, this->xv_port, this->window, this->gc, + this->cur_frame->shmseg, this->cur_frame->xv_format, 0, + 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_frame->xv_width, this->cur_frame->xv_height, 0); + } else { + xcb_xv_put_image(this->connection, this->xv_port, this->window, this->gc, + this->cur_frame->xv_format, + 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_frame->xv_width, this->cur_frame->xv_height, + this->cur_frame->xv_data_size, this->cur_frame->image); + } + + if(this->xoverlay) + xcbosd_expose(this->xoverlay); + + xcb_flush(this->connection); + pthread_mutex_unlock(&this->main_mutex); + } + } + break; + + case XINE_GUI_SEND_DRAWABLE_CHANGED: + pthread_mutex_lock(&this->main_mutex); + this->window = (xcb_window_t) data; + xcb_free_gc(this->connection, this->gc); + this->gc = xcb_generate_id(this->connection); + xcb_create_gc(this->connection, this->gc, this->window, 0, NULL); + if(this->xoverlay) + xcbosd_drawable_changed(this->xoverlay, this->window); + this->ovl_changed = 1; + pthread_mutex_unlock(&this->main_mutex); + this->sc.force_redraw = 1; + break; + + case XINE_GUI_SEND_TRANSLATE_GUI_TO_VIDEO: + { + int x1, y1, x2, y2; + x11_rectangle_t *rect = data; + + _x_vo_scale_translate_gui2video(&this->sc, rect->x, rect->y, + &x1, &y1); + _x_vo_scale_translate_gui2video(&this->sc, rect->x + rect->w, rect->y + rect->h, + &x2, &y2); + rect->x = x1; + rect->y = y1; + rect->w = x2-x1; + rect->h = y2-y1; + + /* onefield_xv divide by 2 the number of lines */ + if (this->deinterlace_enabled + && (this->deinterlace_method == DEINTERLACE_ONEFIELDXV) + && (this->cur_frame->format == XINE_IMGFMT_YV12)) { + rect->y = rect->y * 2; + rect->h = rect->h * 2; + } + + } + break; + + default: + return -1; + } + + return 0; +} + +static void xv_store_port_attribute(xv_driver_t *this, char *name) { + xv_portattribute_t *attr; + + xcb_intern_atom_cookie_t atom_cookie; + xcb_intern_atom_reply_t *atom_reply; + + xcb_xv_get_port_attribute_cookie_t get_attribute_cookie; + xcb_xv_get_port_attribute_reply_t *get_attribute_reply; + + attr = (xv_portattribute_t *)malloc( sizeof(xv_portattribute_t) ); + attr->name = strdup(name); + + pthread_mutex_lock(&this->main_mutex); + atom_cookie = xcb_intern_atom(this->connection, 0, strlen(attr->name), attr->name); + atom_reply = xcb_intern_atom_reply(this->connection, atom_cookie, NULL); + get_attribute_cookie = xcb_xv_get_port_attribute(this->connection, this->xv_port, atom_reply->atom); + get_attribute_reply = xcb_xv_get_port_attribute_reply(this->connection, get_attribute_cookie, NULL); + attr->value = get_attribute_reply->value; + free(atom_reply); + free(get_attribute_reply); + pthread_mutex_unlock(&this->main_mutex); + + xine_list_push_back (this->port_attributes, attr); +} + +static void xv_restore_port_attributes(xv_driver_t *this) { + xine_list_iterator_t ite; + + xcb_intern_atom_cookie_t atom_cookie; + xcb_intern_atom_reply_t *atom_reply; + + while ((ite = xine_list_front(this->port_attributes)) != NULL) { + xv_portattribute_t *attr = xine_list_get_value(this->port_attributes, ite); + xine_list_remove (this->port_attributes, ite); + + pthread_mutex_lock(&this->main_mutex); + atom_cookie = xcb_intern_atom(this->connection, 0, strlen(attr->name), attr->name); + atom_reply = xcb_intern_atom_reply(this->connection, atom_cookie, NULL); + xcb_xv_set_port_attribute(this->connection, this->xv_port, atom_reply->atom, attr->value); + free(atom_reply); + pthread_mutex_unlock(&this->main_mutex); + + free( attr->name ); + free( attr ); + } + + pthread_mutex_lock(&this->main_mutex); + xcb_flush(this->connection); + pthread_mutex_unlock(&this->main_mutex); + + xine_list_delete( this->port_attributes ); +} + +static void xv_dispose (vo_driver_t *this_gen) { + xv_driver_t *this = (xv_driver_t *) this_gen; + int i; + + /* restore port attributes to their initial values */ + xv_restore_port_attributes(this); + + if (this->deinterlace_frame.image) { + pthread_mutex_lock(&this->main_mutex); + dispose_ximage(this, &this->deinterlace_frame); + pthread_mutex_unlock(&this->main_mutex); + } + + pthread_mutex_lock(&this->main_mutex); + xcb_xv_ungrab_port(this->connection, this->xv_port, XCB_CURRENT_TIME); + xcb_free_gc(this->connection, this->gc); + pthread_mutex_unlock(&this->main_mutex); + + 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); + this->recent_frames[i] = NULL; + } + + if( this->xoverlay ) { + pthread_mutex_lock(&this->main_mutex); + xcbosd_destroy(this->xoverlay); + pthread_mutex_unlock(&this->main_mutex); + } + + pthread_mutex_destroy(&this->main_mutex); + + _x_alphablend_free(&this->alphablend_extra_data); + + free (this); +} + +static int xv_check_yv12(xcb_connection_t *connection, xcb_xv_port_t port) { + xcb_xv_list_image_formats_cookie_t list_formats_cookie; + xcb_xv_list_image_formats_reply_t *list_formats_reply; + + xcb_xv_image_format_info_iterator_t format_it; + + list_formats_cookie = xcb_xv_list_image_formats(connection, port); + list_formats_reply = xcb_xv_list_image_formats_reply(connection, list_formats_cookie, NULL); + format_it = xcb_xv_list_image_formats_format_iterator(list_formats_reply); + + for (; format_it.rem; xcb_xv_image_format_info_next(&format_it)) + if ((format_it.data->id == XINE_IMGFMT_YV12) && + (! (strcmp ((char *) format_it.data->guid, "YV12")))) { + free(list_formats_reply); + return 0; + } + + free(list_formats_reply); + return 1; +} + +static void xv_check_capability (xv_driver_t *this, + int property, xcb_xv_attribute_info_t *attr, + int base_id, + char *config_name, + char *config_desc, + char *config_help) { + int int_default; + cfg_entry_t *entry; + char *str_prop = xcb_xv_attribute_info_name(attr); + + xcb_xv_get_port_attribute_cookie_t get_attribute_cookie; + xcb_xv_get_port_attribute_reply_t *get_attribute_reply; + + xcb_intern_atom_cookie_t atom_cookie; + xcb_intern_atom_reply_t *atom_reply; + + /* + * some Xv drivers (Gatos ATI) report some ~0 as max values, this is confusing. + */ + if (VO_PROP_COLORKEY && (attr->max == ~0)) + attr->max = 2147483615; + + atom_cookie = xcb_intern_atom(this->connection, 0, strlen(str_prop), str_prop); + atom_reply = xcb_intern_atom_reply(this->connection, atom_cookie, NULL); + + this->props[property].min = attr->min; + this->props[property].max = attr->max; + this->props[property].atom = atom_reply->atom; + + free(atom_reply); + + get_attribute_cookie = xcb_xv_get_port_attribute(this->connection, this->xv_port, this->props[property].atom); + get_attribute_reply = xcb_xv_get_port_attribute_reply(this->connection, get_attribute_cookie, NULL); + + int_default = get_attribute_reply->value; + + free(get_attribute_reply); + + xprintf(this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xv: port attribute %s (%d) value is %d\n", str_prop, property, int_default); + + /* disable autopaint colorkey by default */ + /* might be overridden using config entry */ + if(strcmp(str_prop, "XV_AUTOPAINT_COLORKEY") == 0) + int_default = 0; + + if (config_name) { + /* is this a boolean property ? */ + if ((attr->min == 0) && (attr->max == 1)) { + this->config->register_bool (this->config, config_name, int_default, + config_desc, + config_help, 20, xv_property_callback, &this->props[property]); + + } else { + this->config->register_range (this->config, config_name, int_default, + this->props[property].min, this->props[property].max, + config_desc, + config_help, 20, xv_property_callback, &this->props[property]); + } + + entry = this->config->lookup_entry (this->config, config_name); + + if((entry->num_value < this->props[property].min) || + (entry->num_value > this->props[property].max)) { + + this->config->update_num(this->config, config_name, + ((this->props[property].min + this->props[property].max) >> 1)); + + entry = this->config->lookup_entry (this->config, config_name); + } + + this->props[property].entry = entry; + + xv_set_property (&this->vo_driver, property, entry->num_value); + + if (strcmp(str_prop, "XV_COLORKEY") == 0) { + this->use_colorkey |= 1; + this->colorkey = entry->num_value; + } else if(strcmp(str_prop, "XV_AUTOPAINT_COLORKEY") == 0) { + if(entry->num_value==1) + this->use_colorkey |= 2; /* colorkey is autopainted */ + } + } else + this->props[property].value = int_default; + +} + +static void xv_update_deinterlace(void *this_gen, xine_cfg_entry_t *entry) { + xv_driver_t *this = (xv_driver_t *) this_gen; + + this->deinterlace_method = entry->num_value; +} + +static void xv_update_XV_FILTER(void *this_gen, xine_cfg_entry_t *entry) { + xv_driver_t *this = (xv_driver_t *) this_gen; + int xv_filter; + + xcb_intern_atom_cookie_t atom_cookie; + xcb_intern_atom_reply_t *atom_reply; + + xv_filter = entry->num_value; + + pthread_mutex_lock(&this->main_mutex); + atom_cookie = xcb_intern_atom(this->connection, 0, sizeof("XV_FILTER"), "XV_FILTER"); + atom_reply = xcb_intern_atom_reply(this->connection, atom_cookie, NULL); + xcb_xv_set_port_attribute(this->connection, this->xv_port, atom_reply->atom, xv_filter); + free(atom_reply); + pthread_mutex_unlock(&this->main_mutex); + + xprintf(this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xv: bilinear scaling mode (XV_FILTER) = %d\n",xv_filter); +} + +static void xv_update_XV_DOUBLE_BUFFER(void *this_gen, xine_cfg_entry_t *entry) { + xv_driver_t *this = (xv_driver_t *) this_gen; + int xv_double_buffer; + + xcb_intern_atom_cookie_t atom_cookie; + xcb_intern_atom_reply_t *atom_reply; + + xv_double_buffer = entry->num_value; + + pthread_mutex_lock(&this->main_mutex); + atom_cookie = xcb_intern_atom(this->connection, 0, sizeof("XV_DOUBLE_BUFFER"), "XV_DOUBLE_BUFFER"); + atom_reply = xcb_intern_atom_reply(this->connection, atom_cookie, NULL); + xcb_xv_set_port_attribute(this->connection, this->xv_port, atom_reply->atom, xv_double_buffer); + free(atom_reply); + pthread_mutex_unlock(&this->main_mutex); + + xprintf(this->xine, XINE_VERBOSITY_DEBUG, + "video_out_xv: double buffering mode = %d\n", xv_double_buffer); +} + +static void xv_update_xv_pitch_alignment(void *this_gen, xine_cfg_entry_t *entry) { + xv_driver_t *this = (xv_driver_t *) this_gen; + + this->use_pitch_alignment = entry->num_value; +} + +static vo_driver_t *open_plugin(video_driver_class_t *class_gen, const void *visual_gen) { + xv_class_t *class = (xv_class_t *) class_gen; + config_values_t *config = class->config; + xv_driver_t *this; + int i; + xcb_visual_t *visual = (xcb_visual_t *) visual_gen; + unsigned int j; + xcb_xv_port_t xv_port; + + const xcb_query_extension_reply_t *query_extension_reply; + + xcb_xv_query_adaptors_cookie_t query_adaptors_cookie; + xcb_xv_query_adaptors_reply_t *query_adaptors_reply; + xcb_xv_query_port_attributes_cookie_t query_attributes_cookie; + xcb_xv_query_port_attributes_reply_t *query_attributes_reply; + xcb_xv_list_image_formats_cookie_t list_formats_cookie; + xcb_xv_list_image_formats_reply_t *list_formats_reply; + + xcb_xv_adaptor_info_iterator_t adaptor_it; + xcb_xv_image_format_info_iterator_t format_it; + + this = (xv_driver_t *) xine_xmalloc (sizeof (xv_driver_t)); + if (!this) + return NULL; + + pthread_mutex_init(&this->main_mutex, NULL); + + _x_alphablend_init(&this->alphablend_extra_data, class->xine); + + this->connection = visual->connection; + this->screen = visual->screen; + this->window = visual->window; + this->config = config; + + /* + * check for Xvideo support + */ + + query_extension_reply = xcb_get_extension_data(this->connection, &xcb_xv_id); + if (!query_extension_reply || !query_extension_reply->present) { + xprintf (class->xine, XINE_VERBOSITY_LOG, _("video_out_xv: Xv extension not present.\n")); + return NULL; + } + + /* + * check adaptors, search for one that supports (at least) yuv12 + */ + + query_adaptors_cookie = xcb_xv_query_adaptors(this->connection, this->window); + query_adaptors_reply = xcb_xv_query_adaptors_reply(this->connection, query_adaptors_cookie, NULL); + + if (!query_adaptors_reply) { + xprintf(class->xine, XINE_VERBOSITY_DEBUG, "video_out_xv: XvQueryAdaptors failed.\n"); + return NULL; + } + + adaptor_it = xcb_xv_query_adaptors_info_iterator(query_adaptors_reply); + + xv_port = 0; + + for (; adaptor_it.rem && !xv_port; xcb_xv_adaptor_info_next(&adaptor_it)) { + + if (adaptor_it.data->type & XCB_XV_TYPE_IMAGE_MASK) { + + for (j = 0; j < adaptor_it.data->num_ports; j++) + if (!xv_check_yv12(this->connection, adaptor_it.data->base_id + j)) { + xcb_xv_grab_port_cookie_t grab_port_cookie; + xcb_xv_grab_port_reply_t *grab_port_reply; + grab_port_cookie = xcb_xv_grab_port(this->connection, adaptor_it.data->base_id + j, XCB_CURRENT_TIME); + grab_port_reply = xcb_xv_grab_port_reply(this->connection, grab_port_cookie, NULL); + if (grab_port_reply && (grab_port_reply->result == XCB_GRAB_STATUS_SUCCESS)) { + free(grab_port_reply); + xv_port = adaptor_it.data->base_id + j; + break; + } + free(grab_port_reply); + } + } + } + + if (!xv_port) { + xprintf(class->xine, XINE_VERBOSITY_LOG, + _("video_out_xv: 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")); + + /* XvFreeAdaptorInfo (adaptor_info); this crashed on me (gb)*/ + return NULL; + } + else + xprintf(class->xine, XINE_VERBOSITY_LOG, + _("video_out_xv: using Xv port %d from adaptor %s for hardware " + "colorspace conversion and scaling.\n"), xv_port, + xcb_xv_adaptor_info_name(adaptor_it.data)); + + this->xv_port = xv_port; + + _x_vo_scale_init (&this->sc, 1, 0, config ); + this->sc.frame_output_cb = visual->frame_output_cb; + this->sc.user_data = visual->user_data; + + this->gc = xcb_generate_id(this->connection); + xcb_create_gc(this->connection, this->gc, this->window, 0, NULL); + this->capabilities = VO_CAP_CROP; + this->use_shm = 1; + this->deinterlace_method = 0; + this->deinterlace_frame.image = NULL; + this->use_colorkey = 0; + this->colorkey = 0; + this->xoverlay = NULL; + this->ovl_changed = 0; + this->xine = class->xine; + + this->vo_driver.get_capabilities = xv_get_capabilities; + this->vo_driver.alloc_frame = xv_alloc_frame; + this->vo_driver.update_frame_format = xv_update_frame_format; + this->vo_driver.overlay_begin = xv_overlay_begin; + this->vo_driver.overlay_blend = xv_overlay_blend; + this->vo_driver.overlay_end = xv_overlay_end; + this->vo_driver.display_frame = xv_display_frame; + this->vo_driver.get_property = xv_get_property; + this->vo_driver.set_property = xv_set_property; + this->vo_driver.get_property_min_max = xv_get_property_min_max; + this->vo_driver.gui_data_exchange = xv_gui_data_exchange; + this->vo_driver.dispose = xv_dispose; + this->vo_driver.redraw_needed = xv_redraw_needed; + + /* + * init properties + */ + + for (i = 0; i < VO_NUM_PROPERTIES; i++) { + this->props[i].value = 0; + this->props[i].min = 0; + this->props[i].max = 0; + this->props[i].atom = XCB_NONE; + this->props[i].entry = NULL; + this->props[i].this = this; + } + + this->props[VO_PROP_INTERLACED].value = 0; + this->sc.user_ratio = + this->props[VO_PROP_ASPECT_RATIO].value = XINE_VO_ASPECT_AUTO; + this->props[VO_PROP_ZOOM_X].value = 100; + this->props[VO_PROP_ZOOM_Y].value = 100; + + /* + * check this adaptor's capabilities + */ + this->port_attributes = xine_list_new(); + + query_attributes_cookie = xcb_xv_query_port_attributes(this->connection, xv_port); + query_attributes_reply = xcb_xv_query_port_attributes_reply(this->connection, query_attributes_cookie, NULL); + if(query_attributes_reply) { + xcb_xv_attribute_info_iterator_t attribute_it; + attribute_it = xcb_xv_query_port_attributes_attributes_iterator(query_attributes_reply); + + for (; attribute_it.rem; xcb_xv_attribute_info_next(&attribute_it)) { + if ((attribute_it.data->flags & XCB_XV_ATTRIBUTE_FLAG_SETTABLE) && (attribute_it.data->flags & XCB_XV_ATTRIBUTE_FLAG_GETTABLE)) { + /* store initial port attribute value */ + xv_store_port_attribute(this, xcb_xv_attribute_info_name(attribute_it.data)); + + if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_HUE")) { + if (!strncmp(xcb_xv_adaptor_info_name(adaptor_it.data), "NV", 2)) { + xprintf (this->xine, XINE_VERBOSITY_NONE, "video_out_xv: ignoring broken XV_HUE settings on NVidia cards"); + } else { + xv_check_capability (this, VO_PROP_HUE, attribute_it.data, + adaptor_it.data->base_id, + NULL, NULL, NULL); + } + } else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_SATURATION")) { + xv_check_capability (this, VO_PROP_SATURATION, attribute_it.data, + adaptor_it.data->base_id, + NULL, NULL, NULL); + + } else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_BRIGHTNESS")) { + xv_check_capability (this, VO_PROP_BRIGHTNESS, attribute_it.data, + adaptor_it.data->base_id, + NULL, NULL, NULL); + + } else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_CONTRAST")) { + xv_check_capability (this, VO_PROP_CONTRAST, attribute_it.data, + adaptor_it.data->base_id, + NULL, NULL, NULL); + + } else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_COLORKEY")) { + xv_check_capability (this, VO_PROP_COLORKEY, attribute_it.data, + adaptor_it.data->base_id, + "video.device.xv_colorkey", + _("video overlay colour key"), + _("The colour key is used to tell the graphics card where to " + "overlay the video image. Try different values, if you experience " + "windows becoming transparent.")); + + } else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_AUTOPAINT_COLORKEY")) { + xv_check_capability (this, VO_PROP_AUTOPAINT_COLORKEY, attribute_it.data, + adaptor_it.data->base_id, + "video.device.xv_autopaint_colorkey", + _("autopaint colour key"), + _("Make Xv autopaint its colorkey.")); + + } else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_FILTER")) { + int xv_filter; + /* This setting is specific to Permedia 2/3 cards. */ + xv_filter = config->register_range (config, "video.device.xv_filter", 0, + attribute_it.data->min, attribute_it.data->max, + _("bilinear scaling mode"), + _("Selects the bilinear scaling mode for Permedia cards. " + "The individual values are:\n\n" + "Permedia 2\n" + "0 - disable bilinear filtering\n" + "1 - enable bilinear filtering\n\n" + "Permedia 3\n" + "0 - disable bilinear filtering\n" + "1 - horizontal linear filtering\n" + "2 - enable full bilinear filtering"), + 20, xv_update_XV_FILTER, this); + config->update_num(config,"video.device.xv_filter",xv_filter); + } else if(!strcmp(xcb_xv_attribute_info_name(attribute_it.data), "XV_DOUBLE_BUFFER")) { + int xv_double_buffer; + xv_double_buffer = + config->register_bool (config, "video.device.xv_double_buffer", 1, + _("enable double buffering"), + _("Double buffering will synchronize the update of the video image to the " + "repainting of the entire screen (\"vertical retrace\"). This eliminates " + "flickering and tearing artifacts, but will use more graphics memory."), + 20, xv_update_XV_DOUBLE_BUFFER, this); + config->update_num(config,"video.device.xv_double_buffer",xv_double_buffer); + } + } + } + free(query_attributes_reply); + } + else + xprintf(this->xine, XINE_VERBOSITY_DEBUG, "video_out_xv: no port attributes defined.\n"); + free(query_adaptors_reply); + + /* + * check supported image formats + */ + + list_formats_cookie = xcb_xv_list_image_formats(this->connection, xv_port); + list_formats_reply = xcb_xv_list_image_formats_reply(this->connection, list_formats_cookie, NULL); + + format_it = xcb_xv_list_image_formats_format_iterator(list_formats_reply); + + this->xv_format_yv12 = 0; + this->xv_format_yuy2 = 0; + + for (; format_it.rem; xcb_xv_image_format_info_next(&format_it)) { + lprintf ("Xv image format: 0x%x (%4.4s) %s\n", + format_it.data->id, (char*)&format_it.data->id, + (format_it.data->format == XvPacked) ? "packed" : "planar"); + + if (format_it.data->id == XINE_IMGFMT_YV12) { + this->xv_format_yv12 = format_it.data->id; + this->capabilities |= VO_CAP_YV12; + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("video_out_xv: this adaptor supports the yv12 format.\n")); + } else if (format_it.data->id == XINE_IMGFMT_YUY2) { + this->xv_format_yuy2 = format_it.data->id; + this->capabilities |= VO_CAP_YUY2; + xprintf(this->xine, XINE_VERBOSITY_LOG, + _("video_out_xv: this adaptor supports the yuy2 format.\n")); + } + } + + free(list_formats_reply); + + this->use_pitch_alignment = + config->register_bool (config, "video.device.xv_pitch_alignment", 0, + _("pitch alignment workaround"), + _("Some buggy video drivers need a workaround to function properly."), + 10, xv_update_xv_pitch_alignment, this); + + this->deinterlace_method = + config->register_enum (config, "video.output.xv_deinterlace_method", 4, + deinterlace_methods, + _("deinterlace method (deprecated)"), + _("This config setting is deprecated. You should use the new deinterlacing " + "post processing settings instead.\n\n" + "From the old days of analog television, where the even and odd numbered " + "lines of a video frame would be displayed at different times comes the " + "idea to increase motion smoothness by also recording the lines at " + "different times. This is called \"interlacing\". But unfortunately, " + "todays displays show the even and odd numbered lines as one complete frame " + "all at the same time (called \"progressive display\"), which results in " + "ugly frame errors known as comb artifacts. Software deinterlacing is an " + "approach to reduce these artifacts. The individual values are:\n\n" + "none\n" + "Disables software deinterlacing.\n\n" + "bob\n" + "Interpolates between the lines for moving parts of the image.\n\n" + "weave\n" + "Similar to bob, but with a tendency to preserve the full resolution, " + "better for high detail in low movement scenes.\n\n" + "greedy\n" + "Very good adaptive deinterlacer, but needs a lot of CPU power.\n\n" + "onefield\n" + "Always interpolates and reduces vertical resolution.\n\n" + "onefieldxv\n" + "Same as onefield, but does the interpolation in hardware.\n\n" + "linearblend\n" + "Applies a slight vertical blur to remove the comb artifacts. Good results " + "with medium CPU usage."), + 10, xv_update_deinterlace, this); + this->deinterlace_enabled = 0; + + if(this->use_colorkey==1) { + this->xoverlay = xcbosd_create(this->xine, this->connection, this->screen, + this->window, XCBOSD_COLORKEY); + if(this->xoverlay) + xcbosd_colorkey(this->xoverlay, this->colorkey, &this->sc); + } else { + this->xoverlay = xcbosd_create(this->xine, this->connection, this->screen, + this->window, XCBOSD_SHAPED); + } + + if( this->xoverlay ) + this->capabilities |= VO_CAP_UNSCALED_OVERLAY; + + return &this->vo_driver; +} + +/* + * class functions + */ + +static char* get_identifier (video_driver_class_t *this_gen) { + return "Xv"; +} + +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) { + xv_class_t *this = (xv_class_t *) this_gen; + + free (this); +} + +static void *init_class (xine_t *xine, void *visual_gen) { + xv_class_t *this = (xv_class_t *) xine_xmalloc (sizeof (xv_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->config = xine->config; + this->xine = xine; + + return this; +} + +static const vo_info_t vo_info_xv = { + 9, /* priority */ + XINE_VISUAL_TYPE_XCB /* visual type */ +}; + +/* + * exported plugin catalog entry + */ + +const plugin_info_t xine_plugin_info[] EXPORTED = { + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_VIDEO_OUT, 21, "xv", XINE_VERSION_CODE, &vo_info_xv, init_class }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } +}; + +#endif Index: src/video_out/video_out_xshm.c =================================================================== RCS file: /cvsroot/xine/xine-lib/src/video_out/video_out_xshm.c,v retrieving revision 1.148 diff -u -B -r1.148 video_out_xshm.c --- src/video_out/video_out_xshm.c 28 Oct 2006 18:51:08 -0000 1.148 +++ src/video_out/video_out_xshm.c 7 Feb 2007 02:41:42 -0000 @@ -87,7 +87,6 @@ yuv2rgb_t *yuv2rgb; /* yuv2rgb converter set up for this frame */ uint8_t *rgb_dst; - int yuv_stride; } xshm_frame_t; @@ -105,8 +104,6 @@ int use_shm; XColor black; - int yuv2rgb_mode; - int yuv2rgb_swap; int yuv2rgb_brightness; int yuv2rgb_contrast; int yuv2rgb_saturation; @@ -585,7 +582,6 @@ frame->sc.output_width, frame->sc.output_height, frame->image->bytes_per_line*2); - frame->yuv_stride = frame->image->bytes_per_line*2; break; case VO_BOTH_FIELDS: frame->yuv2rgb->configure (frame->yuv2rgb, @@ -596,7 +592,6 @@ frame->sc.output_width, frame->sc.output_height, frame->image->bytes_per_line); - frame->yuv_stride = frame->image->bytes_per_line; break; } } @@ -1255,8 +1250,6 @@ return NULL; } - this->yuv2rgb_mode = mode; - this->yuv2rgb_swap = swapped; this->yuv2rgb_brightness = 0; this->yuv2rgb_contrast = 128; this->yuv2rgb_saturation = 128; Index: src/video_out/xcbosd.c =================================================================== RCS file: src/video_out/xcbosd.c diff -N src/video_out/xcbosd.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/video_out/xcbosd.c 7 Feb 2007 02:41:42 -0000 @@ -0,0 +1,546 @@ +/* + * Copyright (C) 2003, 2007 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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: xine-lib-1.1.4-xcb.patch,v 1.1 2007-05-08 20:43:46 niro Exp $ + * + * xcbosd.c, use X11 Nonrectangular Window Shape Extension to draw xine OSD + * + * Nov 2003 - Miguel Freitas + * Feb 2007 - ported to xcb by Christoph Pfister + * + * based on ideas and code of + * xosd Copyright (c) 2000 Andre Renaud (andre@ignavus.net) + * + * colorkey support by Yann Vernier + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#define LOG_MODULE "xcbosd" +#define LOG_VERBOSE + +/* +#define LOG +*/ + +#include "xine_internal.h" +#include "xcbosd.h" + +struct xcbosd +{ + xcb_connection_t *connection; + xcb_screen_t *screen; + enum xcbosd_mode mode; + + union { + struct { + xcb_window_t window; + xcb_pixmap_t mask_bitmap; + xcb_gc_t mask_gc; + xcb_gc_t mask_gc_back; + int mapped; + } shaped; + struct { + uint32_t colorkey; + vo_scale_t *sc; + } colorkey; + } u; + xcb_window_t window; + unsigned int depth; + xcb_pixmap_t bitmap; + xcb_visualid_t visual; + xcb_colormap_t cmap; + + xcb_gc_t gc; + + int width; + int height; + int x; + int y; + enum {DRAWN, WIPED, UNDEFINED} clean; + xine_t *xine; +}; + + +void xcbosd_expose(xcbosd *osd) +{ + assert (osd); + + lprintf("expose (state:%d)\n", osd->clean ); + + switch (osd->mode) { + case XCBOSD_SHAPED: + xcb_shape_mask(osd->connection, XCB_SHAPE_SO_SET, XCB_SHAPE_SK_BOUNDING, + osd->u.shaped.window, 0, 0, osd->u.shaped.mask_bitmap); + if( osd->clean==DRAWN ) { + + if( !osd->u.shaped.mapped ) { + unsigned int stack_mode = XCB_STACK_MODE_ABOVE; + xcb_configure_window(osd->connection, osd->u.shaped.window, XCB_CONFIG_WINDOW_STACK_MODE, &stack_mode); + xcb_map_window(osd->connection, osd->u.shaped.window); + } + osd->u.shaped.mapped = 1; + + xcb_copy_area(osd->connection, osd->bitmap, osd->u.shaped.window, + osd->gc, 0, 0, 0, 0, osd->width, osd->height); + } else { + if( osd->u.shaped.mapped ) + xcb_unmap_window(osd->connection, osd->u.shaped.window); + osd->u.shaped.mapped = 0; + } + break; + case XCBOSD_COLORKEY: + if( osd->clean!=UNDEFINED ) + xcb_copy_area(osd->connection, osd->bitmap, osd->window, osd->gc, 0, 0, + 0, 0, osd->width, osd->height); + } +} + + +void xcbosd_resize(xcbosd *osd, int width, int height) +{ + assert (osd); + assert (width); + assert (height); + + lprintf("resize old:%dx%d new:%dx%d\n", osd->width, osd->height, width, height ); + + osd->width = width; + osd->height = height; + + xcb_free_pixmap(osd->connection, osd->bitmap); + switch(osd->mode) { + case XCBOSD_SHAPED: { + unsigned int window_config[] = { osd->width, osd->height }; + xcb_configure_window(osd->connection, osd->u.shaped.window, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, window_config); + xcb_free_pixmap(osd->connection, osd->u.shaped.mask_bitmap); + osd->u.shaped.mask_bitmap = xcb_generate_id(osd->connection); + xcb_create_pixmap(osd->connection, 1, osd->u.shaped.mask_bitmap, osd->u.shaped.window, osd->width, osd->height); + osd->bitmap = xcb_generate_id(osd->connection); + xcb_create_pixmap(osd->connection, osd->depth, osd->bitmap, osd->u.shaped.window, osd->width, osd->height); + break; + } + case XCBOSD_COLORKEY: + osd->bitmap = xcb_generate_id(osd->connection); + xcb_create_pixmap(osd->connection, osd->depth, osd->bitmap, osd->window, osd->width, osd->height); + break; + } + + osd->clean = UNDEFINED; + xcbosd_clear(osd); +} + +void xcbosd_drawable_changed(xcbosd *osd, xcb_window_t window) +{ + xcb_get_geometry_cookie_t get_geometry_cookie; + xcb_get_geometry_reply_t *get_geometry_reply; + + assert (osd); + + lprintf("drawable changed\n"); + +/* + Do I need to recreate the GC's?? + + XFreeGC (osd->display, osd->gc); + XFreeGC (osd->display, osd->mask_gc); + XFreeGC (osd->display, osd->mask_gc_back); +*/ + xcb_free_pixmap(osd->connection, osd->bitmap); + xcb_free_colormap(osd->connection, osd->cmap); + + /* we need to call XSync(), because otherwise, calling XDestroyWindow() + on the parent window could destroy our OSD window twice !! */ + /* XSync (osd->display, False); FIXME don't think that we need that --pfister */ + + osd->window = window; + + get_geometry_cookie = xcb_get_geometry(osd->connection, osd->window); + get_geometry_reply = xcb_get_geometry_reply(osd->connection, get_geometry_cookie, NULL); + osd->depth = get_geometry_reply->depth; + osd->width = get_geometry_reply->width; + osd->height = get_geometry_reply->height; + free(get_geometry_reply); + + assert(osd->width); + assert(osd->height); + + switch(osd->mode) { + case XCBOSD_SHAPED: { + xcb_free_pixmap(osd->connection, osd->u.shaped.mask_bitmap); + xcb_destroy_window(osd->connection, osd->u.shaped.window); + + unsigned int window_params[] = { osd->screen->black_pixel, 1, XCB_EVENT_MASK_EXPOSURE }; + osd->u.shaped.window = xcb_generate_id(osd->connection); + xcb_create_window(osd->connection, XCB_COPY_FROM_PARENT, osd->u.shaped.window, + osd->window, 0, 0, osd->width, osd->height, 0, XCB_COPY_FROM_PARENT, + XCB_COPY_FROM_PARENT, XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK, + window_params); + + osd->u.shaped.mapped = 0; + + osd->u.shaped.mask_bitmap = xcb_generate_id(osd->connection); + xcb_create_pixmap(osd->connection, 1, osd->u.shaped.mask_bitmap, osd->u.shaped.window, osd->width, osd->height); + + osd->bitmap = xcb_generate_id(osd->connection); + xcb_create_pixmap(osd->connection, osd->depth, osd->bitmap, osd->u.shaped.window, osd->width, osd->height); + + osd->cmap = xcb_generate_id(osd->connection); + xcb_create_colormap(osd->connection, XCB_COLORMAP_ALLOC_NONE, osd->cmap, osd->u.shaped.window, osd->visual); + break; + } + case XCBOSD_COLORKEY: + osd->bitmap = xcb_generate_id(osd->connection); + xcb_create_pixmap(osd->connection, osd->depth, osd->bitmap, osd->window, osd->width, osd->height); + osd->cmap = xcb_generate_id(osd->connection); + xcb_create_colormap(osd->connection, XCB_COLORMAP_ALLOC_NONE, osd->cmap, osd->window, osd->visual); + + break; + } + + osd->clean = UNDEFINED; + /* do not xcbosd_clear() here: osd->u.colorkey.sc has not being updated yet */ +} + +xcbosd *xcbosd_create(xine_t *xine, xcb_connection_t *connection, xcb_screen_t *screen, xcb_window_t window, enum xcbosd_mode mode) +{ + xcbosd *osd; + + xcb_get_geometry_cookie_t get_geometry_cookie; + xcb_get_geometry_reply_t *get_geometry_reply; + + xcb_void_cookie_t generic_cookie; + xcb_generic_error_t *generic_error; + + osd = xine_xmalloc (sizeof (xcbosd)); + if (!osd) + return NULL; + + osd->mode = mode; + osd->xine = xine; + osd->connection = connection; + osd->screen = screen; + osd->window = window; + + osd->visual = osd->screen->root_visual; + + get_geometry_cookie = xcb_get_geometry(osd->connection, osd->window); + get_geometry_reply = xcb_get_geometry_reply(osd->connection, get_geometry_cookie, NULL); + osd->depth = get_geometry_reply->depth; + osd->width = get_geometry_reply->width; + osd->height = get_geometry_reply->height; + free(get_geometry_reply); + + assert(osd->width); + assert(osd->height); + + switch (mode) { + case XCBOSD_SHAPED: { + const xcb_query_extension_reply_t *query_extension_reply = xcb_get_extension_data(osd->connection, &xcb_shape_id); + + if (!query_extension_reply || !query_extension_reply->present) { + xprintf(osd->xine, XINE_VERBOSITY_LOG, _("x11osd: XShape extension not available. unscaled overlay disabled.\n")); + goto error2; + } + + unsigned int window_params[] = { osd->screen->black_pixel, 1, XCB_EVENT_MASK_EXPOSURE }; + osd->u.shaped.window = xcb_generate_id(osd->connection); + generic_cookie = xcb_create_window_checked(osd->connection, XCB_COPY_FROM_PARENT, osd->u.shaped.window, + osd->window, 0, 0, osd->width, osd->height, 0, XCB_COPY_FROM_PARENT, + XCB_COPY_FROM_PARENT, XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK, + window_params); + generic_error = xcb_request_check(osd->connection, generic_cookie); + + if (generic_error != NULL) { + xprintf(osd->xine, XINE_VERBOSITY_LOG, _("x11osd: error creating window. unscaled overlay disabled.\n")); + free(generic_error); + goto error_window; + } + + osd->u.shaped.mask_bitmap = xcb_generate_id(osd->connection); + generic_cookie = xcb_create_pixmap_checked(osd->connection, 1, osd->u.shaped.mask_bitmap, osd->u.shaped.window, osd->width, osd->height); + generic_error = xcb_request_check(osd->connection, generic_cookie); + + if (generic_error != NULL) { + xprintf(osd->xine, XINE_VERBOSITY_LOG, _("x11osd: error creating pixmap. unscaled overlay disabled.\n")); + free(generic_error); + goto error_aftermaskbitmap; + } + + osd->bitmap = xcb_generate_id(osd->connection); + xcb_create_pixmap(osd->connection, osd->depth, osd->bitmap, osd->u.shaped.window, osd->width, osd->height); + osd->gc = xcb_generate_id(osd->connection); + xcb_create_gc(osd->connection, osd->gc, osd->u.shaped.window, 0, NULL); + + osd->u.shaped.mask_gc = xcb_generate_id(osd->connection); + xcb_create_gc(osd->connection, osd->u.shaped.mask_gc, osd->u.shaped.mask_bitmap, XCB_GC_FOREGROUND, &osd->screen->white_pixel); + + osd->u.shaped.mask_gc_back = xcb_generate_id(osd->connection); + xcb_create_gc(osd->connection, osd->u.shaped.mask_gc_back, osd->u.shaped.mask_bitmap, XCB_GC_FOREGROUND, &osd->screen->black_pixel); + + osd->u.shaped.mapped = 0; + osd->cmap = xcb_generate_id(osd->connection); + xcb_create_colormap(osd->connection, XCB_COLORMAP_ALLOC_NONE, osd->cmap, osd->u.shaped.window, osd->visual); + break; + } + case XCBOSD_COLORKEY: + osd->bitmap = xcb_generate_id(osd->connection); + xcb_create_pixmap(osd->connection, osd->depth, osd->bitmap, osd->window, osd->width, osd->height); + osd->gc = xcb_generate_id(osd->connection); + xcb_create_gc(osd->connection, osd->gc, osd->window, 0, NULL); + osd->cmap = xcb_generate_id(osd->connection); + xcb_create_colormap(osd->connection, XCB_COLORMAP_ALLOC_NONE, osd->cmap, osd->window, osd->visual); + /* FIXME: the expose event doesn't seem to happen? */ + /*XSelectInput (osd->display, osd->window, ExposureMask);*/ + break; + default: + goto error2; + } + + osd->clean = UNDEFINED; + xcbosd_expose(osd); + + xprintf(osd->xine, XINE_VERBOSITY_DEBUG, + _("x11osd: unscaled overlay created (%s mode).\n"), + (mode==XCBOSD_SHAPED) ? "XShape" : "Colorkey" ); + + return osd; + +/* + XFreeGC (osd->display, osd->gc); + XFreeGC (osd->display, osd->mask_gc); + XFreeGC (osd->display, osd->mask_gc_back); +*/ + +error_aftermaskbitmap: + if(mode==XCBOSD_SHAPED) + xcb_free_pixmap(osd->connection, osd->u.shaped.mask_bitmap); +error_window: + if(mode==XCBOSD_SHAPED) + xcb_destroy_window(osd->connection, osd->u.shaped.window); +error2: + free (osd); + return NULL; +} + +void xcbosd_colorkey(xcbosd *osd, uint32_t colorkey, vo_scale_t *scaling) +{ + assert (osd); + assert (osd->mode==XCBOSD_COLORKEY); + + osd->u.colorkey.colorkey=colorkey; + osd->u.colorkey.sc=scaling; + osd->clean = UNDEFINED; + xcbosd_clear(osd); + xcbosd_expose(osd); +} + +void xcbosd_destroy(xcbosd *osd) +{ + + assert (osd); + + xcb_free_gc(osd->connection, osd->gc); + xcb_free_pixmap(osd->connection, osd->bitmap); + xcb_free_colormap(osd->connection, osd->cmap); + if(osd->mode==XCBOSD_SHAPED) { + xcb_free_gc(osd->connection, osd->u.shaped.mask_gc); + xcb_free_gc(osd->connection, osd->u.shaped.mask_gc_back); + xcb_free_pixmap(osd->connection, osd->u.shaped.mask_bitmap); + xcb_destroy_window(osd->connection, osd->u.shaped.window); + } + + free (osd); +} + +void xcbosd_clear(xcbosd *osd) +{ + int i; + + lprintf("clear (state:%d)\n", osd->clean ); + + if( osd->clean != WIPED ) + switch (osd->mode) { + case XCBOSD_SHAPED: { + xcb_rectangle_t rectangle = { 0, 0, osd->width, osd->height }; + xcb_poly_fill_rectangle(osd->connection, osd->u.shaped.mask_bitmap, osd->u.shaped.mask_gc_back, 1, &rectangle); + break; + } + case XCBOSD_COLORKEY: + xcb_change_gc(osd->connection, osd->gc, XCB_GC_FOREGROUND, &osd->u.colorkey.colorkey); + if(osd->u.colorkey.sc) { + xcb_rectangle_t rectangle = { osd->u.colorkey.sc->output_xoffset, osd->u.colorkey.sc->output_yoffset, + osd->u.colorkey.sc->output_width, osd->u.colorkey.sc->output_height }; + xcb_poly_fill_rectangle(osd->connection, osd->bitmap, osd->gc, 1, &rectangle); + xcb_change_gc(osd->connection, osd->gc, XCB_GC_FOREGROUND, &osd->screen->black_pixel); + + xcb_rectangle_t rects[4]; + int rects_count = 0; + + for( i = 0; i < 4; i++ ) { + if( osd->u.colorkey.sc->border[i].w && osd->u.colorkey.sc->border[i].h ) { + rects[rects_count].x = osd->u.colorkey.sc->border[i].x; + rects[rects_count].y = osd->u.colorkey.sc->border[i].y; + rects[rects_count].width = osd->u.colorkey.sc->border[i].w; + rects[rects_count].height = osd->u.colorkey.sc->border[i].h; + rects_count++; + } + + if (rects_count > 0) + xcb_poly_fill_rectangle(osd->connection, osd->bitmap, osd->gc, rects_count, rects); + } + } else { + xcb_rectangle_t rectangle = { 0, 0, osd->width, osd->height }; + xcb_poly_fill_rectangle(osd->connection, osd->bitmap, osd->gc, 1, &rectangle); + } + break; + } + osd->clean = WIPED; +} + +#define TRANSPARENT 0xffffffff + +#define saturate(n, l, u) ((n) < (l) ? (l) : ((n) > (u) ? (u) : (n))) + +void xcbosd_blend(xcbosd *osd, vo_overlay_t *overlay) +{ + xcb_alloc_color_cookie_t alloc_color_cookie; + xcb_alloc_color_reply_t *alloc_color_reply; + + if (osd->clean==UNDEFINED) + xcbosd_clear(osd); /* Workaround. Colorkey mode needs sc data before the clear. */ + + if (overlay->rle) { + int i, x, y, len, width; + int use_clip_palette, max_palette_colour[2]; + uint32_t palette[2][OVL_PALETTE_SIZE]; + + max_palette_colour[0] = -1; + max_palette_colour[1] = -1; + + for (i=0, x=0, y=0; inum_rle; i++) { + len = overlay->rle[i].len; + + while (len > 0) { + use_clip_palette = 0; + if (len > overlay->width) { + width = overlay->width; + len -= overlay->width; + } + else { + width = len; + len = 0; + } + if ((y >= overlay->hili_top) && (y <= overlay->hili_bottom) && (x <= overlay->hili_right)) { + if ((x < overlay->hili_left) && (x + width - 1 >= overlay->hili_left)) { + width -= overlay->hili_left - x; + len += overlay->hili_left - x; + } + else if (x > overlay->hili_left) { + use_clip_palette = 1; + if (x + width - 1 > overlay->hili_right) { + width -= overlay->hili_right - x; + len += overlay->hili_right - x; + } + } + } + + if (overlay->rle[i].color > max_palette_colour[use_clip_palette]) { + int j; + clut_t *src_clut; + uint8_t *src_trans; + + if (use_clip_palette) { + src_clut = (clut_t *)&overlay->hili_color; + src_trans = (uint8_t *)&overlay->hili_trans; + } + else { + src_clut = (clut_t *)&overlay->color; + src_trans = (uint8_t *)&overlay->trans; + } + for (j=max_palette_colour[use_clip_palette]+1; j<=overlay->rle[i].color; j++) { + if (src_trans[j]) { + if (1) { + int red, green, blue; + int y, u, v, r, g, b; + + y = saturate(src_clut[j].y, 16, 235); + u = saturate(src_clut[j].cb, 16, 240); + v = saturate(src_clut[j].cr, 16, 240); + y = (9 * y) / 8; + r = y + (25 * v) / 16 - 218; + red = (65536 * saturate(r, 0, 255)) / 256; + g = y + (-13 * v) / 16 + (-25 * u) / 64 + 136; + green = (65536 * saturate(g, 0, 255)) / 256; + b = y + 2 * u - 274; + blue = (65536 * saturate(b, 0, 255)) / 256; + + alloc_color_cookie = xcb_alloc_color(osd->connection, osd->cmap, red, green, blue); + alloc_color_reply = xcb_alloc_color_reply(osd->connection, alloc_color_cookie, NULL); + + palette[use_clip_palette][j] = alloc_color_reply->pixel; + free(alloc_color_reply); + } + else { + if (src_clut[j].y > 127) { + palette[use_clip_palette][j] = osd->screen->white_pixel; + } + else { + palette[use_clip_palette][j] = osd->screen->black_pixel; + } + } + } + else { + palette[use_clip_palette][j] = TRANSPARENT; + } + } + max_palette_colour[use_clip_palette] = overlay->rle[i].color; + } + + if(palette[use_clip_palette][overlay->rle[i].color] != TRANSPARENT) { + xcb_change_gc(osd->connection, osd->gc, XCB_GC_FOREGROUND, &palette[use_clip_palette][overlay->rle[i].color]); + xcb_rectangle_t rectangle = { overlay->x + x, overlay->y + y, width, 1 }; + xcb_poly_fill_rectangle(osd->connection, osd->bitmap, osd->gc, 1, &rectangle); + if(osd->mode==XCBOSD_SHAPED) + xcb_poly_fill_rectangle(osd->connection, osd->u.shaped.mask_bitmap, osd->u.shaped.mask_gc, 1, &rectangle); + } + + x += width; + if (x == overlay->width) { + x = 0; + y++; + } + } + } + osd->clean = DRAWN; + } +} + Index: src/video_out/xcbosd.h =================================================================== RCS file: src/video_out/xcbosd.h diff -N src/video_out/xcbosd.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ src/video_out/xcbosd.h 7 Feb 2007 02:41:42 -0000 @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2003, 2007 the xine project + * + * This file is part of xine, a free video player. + * + * xine is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xine is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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: xine-lib-1.1.4-xcb.patch,v 1.1 2007-05-08 20:43:46 niro Exp $ + * + * xcbosd.h, use X11 Nonrectangular Window Shape Extension to draw xine OSD + * + * Nov 2003 - Miguel Freitas + * Feb 2007 - ported to xcb by Christoph Pfister + * + * based on ideas and code of + * xosd Copyright (c) 2000 Andre Renaud (andre@ignavus.net) + */ + +#ifndef XCBOSD_H +#define XCBOSD_H + +#include "vo_scale.h" + +typedef struct xcbosd xcbosd; +enum xcbosd_mode {XCBOSD_SHAPED, XCBOSD_COLORKEY}; + +xcbosd *xcbosd_create(xine_t *xine, xcb_connection_t *connection, xcb_screen_t *screen, xcb_window_t window, enum xcbosd_mode mode); + +void xcbosd_colorkey(xcbosd *osd, uint32_t colorkey, vo_scale_t *scaling); + +void xcbosd_destroy(xcbosd *osd); + +void xcbosd_expose(xcbosd *osd); + +void xcbosd_resize(xcbosd *osd, int width, int height); + +void xcbosd_drawable_changed(xcbosd *osd, xcb_window_t window); + +void xcbosd_clear(xcbosd *osd); + +void xcbosd_blend(xcbosd *osd, vo_overlay_t *overlay); + +#endif