summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/video_out/Makefile.am24
-rw-r--r--src/video_out/video_out_xcbshm.c1274
-rw-r--r--src/video_out/video_out_xcbxv.c1598
-rw-r--r--src/video_out/video_out_xshm.c9
-rw-r--r--src/video_out/xcbosd.c546
-rw-r--r--src/video_out/xcbosd.h55
6 files changed, 3497 insertions, 9 deletions
diff --git a/src/video_out/Makefile.am b/src/video_out/Makefile.am
index 45b5dac8c..041184e8c 100644
--- a/src/video_out/Makefile.am
+++ b/src/video_out/Makefile.am
@@ -37,6 +37,16 @@ endif
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 @@ lib_LTLIBRARIES = $(xshm_module) $(xv_module) $(xvmc_module) \
$(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 @@ xineplug_vo_out_macosx_la_LDFLAGS = -avoid-version -module \
-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
diff --git a/src/video_out/video_out_xcbshm.c b/src/video_out/video_out_xcbshm.c
new file mode 100644
index 000000000..3e45c7fdb
--- /dev/null
+++ b/src/video_out/video_out_xcbshm.c
@@ -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: video_out_xcbshm.c,v 1.1 2007/02/15 15:19:33 dgp85 Exp $
+ *
+ * video_out_xcbshm.c, X11 shared memory extension interface for xine
+ *
+ * based on mpeg2dec code from
+ * Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * xine-specific code by Guenter Bartsch <bartscgr@studbox.uni-stuttgart.de>
+ *
+ * ported to xcb by Christoph Pfister - Feb 2007
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "xine.h"
+#include "video_out.h"
+
+#include <errno.h>
+
+#include <xcb/shm.h>
+
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/time.h>
+
+#include <pthread.h>
+#include <netinet/in.h>
+
+#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 }
+};
diff --git a/src/video_out/video_out_xcbxv.c b/src/video_out/video_out_xcbxv.c
new file mode 100644
index 000000000..6b8bc3919
--- /dev/null
+++ b/src/video_out/video_out_xcbxv.c
@@ -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: video_out_xcbxv.c,v 1.1 2007/02/15 15:19:33 dgp85 Exp $
+ *
+ * video_out_xcbxv.c, X11 video extension interface for xine
+ *
+ * based on mpeg2dec code from
+ * Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
+ *
+ * Xv image support by Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ * xine-specific code by Guenter Bartsch <bartscgr@studbox.uni-stuttgart.de>
+ *
+ * overlay support by James Courtier-Dutton <James@superbug.demon.co.uk> - 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+
+#include <sys/types.h>
+#if defined(__FreeBSD__)
+#include <machine/param.h>
+#endif
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/time.h>
+
+#include <xcb/xv.h>
+
+#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
diff --git a/src/video_out/video_out_xshm.c b/src/video_out/video_out_xshm.c
index d109fb455..579189825 100644
--- a/src/video_out/video_out_xshm.c
+++ b/src/video_out/video_out_xshm.c
@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: video_out_xshm.c,v 1.148 2006/10/28 18:51:08 miguelfreitas Exp $
+ * $Id: video_out_xshm.c,v 1.149 2007/02/15 15:19:33 dgp85 Exp $
*
* video_out_xshm.c, X11 shared memory extension interface for xine
*
@@ -87,7 +87,6 @@ typedef struct {
yuv2rgb_t *yuv2rgb; /* yuv2rgb converter set up for this frame */
uint8_t *rgb_dst;
- int yuv_stride;
} xshm_frame_t;
@@ -105,8 +104,6 @@ typedef struct {
int use_shm;
XColor black;
- int yuv2rgb_mode;
- int yuv2rgb_swap;
int yuv2rgb_brightness;
int yuv2rgb_contrast;
int yuv2rgb_saturation;
@@ -585,7 +582,6 @@ static void xshm_update_frame_format (vo_driver_t *this_gen,
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 @@ static void xshm_update_frame_format (vo_driver_t *this_gen,
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 @@ static vo_driver_t *xshm_open_plugin_2 (video_driver_class_t *class_gen, const v
return NULL;
}
- this->yuv2rgb_mode = mode;
- this->yuv2rgb_swap = swapped;
this->yuv2rgb_brightness = 0;
this->yuv2rgb_contrast = 128;
this->yuv2rgb_saturation = 128;
diff --git a/src/video_out/xcbosd.c b/src/video_out/xcbosd.c
new file mode 100644
index 000000000..9013bab10
--- /dev/null
+++ b/src/video_out/xcbosd.c
@@ -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: xcbosd.c,v 1.1 2007/02/15 15:19:33 dgp85 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 <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <time.h>
+
+#include <assert.h>
+
+#include <netinet/in.h>
+
+#include <xcb/shape.h>
+
+#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; i<overlay->num_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;
+ }
+}
+
diff --git a/src/video_out/xcbosd.h b/src/video_out/xcbosd.h
new file mode 100644
index 000000000..f948c9baf
--- /dev/null
+++ b/src/video_out/xcbosd.h
@@ -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: xcbosd.h,v 1.1 2007/02/15 15:19:33 dgp85 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