summaryrefslogtreecommitdiff
path: root/src/video_out/video_out_xv.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_out/video_out_xv.c')
-rw-r--r--src/video_out/video_out_xv.c903
1 files changed, 903 insertions, 0 deletions
diff --git a/src/video_out/video_out_xv.c b/src/video_out/video_out_xv.c
new file mode 100644
index 000000000..00cc8c18d
--- /dev/null
+++ b/src/video_out/video_out_xv.c
@@ -0,0 +1,903 @@
+/*
+ * Copyright (C) 2000 the xine project
+ *
+ * This file is part of xine, a unix 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_xv.c,v 1.1 2001/04/24 20:53:00 f1rmb Exp $
+ *
+ * video_out_xv.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>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_XV
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/cursorfont.h>
+#include <X11/extensions/XShm.h>
+#include <X11/extensions/Xv.h>
+#include <X11/extensions/Xvlib.h>
+#ifdef HAVE_XINERAMA
+#include <X11/extensions/Xinerama.h>
+#endif
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/time.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "video_out.h"
+
+/* override xprintf definition */
+#define xprintf(LVL, FMT, ARGS...) { printf(FMT, ##ARGS); }
+
+typedef struct xv_property_s {
+ int value;
+ int min;
+ int max;
+ Atom atom;
+ char *key;
+} xv_property_t;
+
+typedef struct xv_frame_s {
+ vo_frame_t vo_frame;
+
+ int width, height, ratio_code, format;
+
+ XvImage *image;
+ XShmSegmentInfo shminfo;
+
+} xv_frame_t;
+
+typedef struct xv_driver_s {
+
+ vo_driver_t vo_driver;
+
+ config_values_t *config;
+
+ /* X11 / Xv related stuff */
+ Display *display;
+ int screen;
+ unsigned int xv_format_rgb, xv_format_yv12, xv_format_yuy2;
+ int depth;
+ XColor black;
+ XVisualInfo vinfo;
+ Window window;
+ XClassHint *xclasshint;
+ GC gc;
+ int CompletionType;
+ unsigned int xv_port;
+
+ xv_property_t props[VO_NUM_PROPERTIES];
+ uint32_t capabilities;
+
+ xv_frame_t *cur_frame;
+
+ /* size / aspect ratio calculations */
+ int delivered_width; /* everything is set up for these frame dimensions */
+ int delivered_height; /* the dimension as they come from the decoder */
+ int delivered_ratio_code;
+ double ratio_factor; /* output frame must fullfill: height = width * ratio_factor */
+ int output_width; /* frames will appear in this size (pixels) on screen */
+ int output_height;
+ int output_xoffset;
+ int output_yoffset;
+
+ /* display anatomy */
+ double display_ratio; /* calced from display resolution */
+ int fullscreen_width; /* this is basically how big the screen is */
+ int fullscreen_height;
+ int in_fullscreen; /* is the window in fullscreen mode? */
+} xv_driver_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 vo_frame_t *xv_alloc_frame (vo_driver_t *this_gen) {
+
+ xv_frame_t *frame ;
+
+ frame = (xv_frame_t *) malloc (sizeof (xv_frame_t));
+ memset (frame, 0, sizeof(xv_frame_t));
+
+ if (frame==NULL) {
+ printf ("xv_alloc_frame: out of memory\n");
+ }
+
+ pthread_mutex_init (&frame->vo_frame.mutex, NULL);
+
+ return (vo_frame_t *) frame;
+}
+
+static void xv_update_frame_format (vo_driver_t *this_gen, vo_frame_t *frame_gen,
+ uint32_t width, uint32_t height, int ratio_code,
+ int format) {
+
+ xv_driver_t *this = (xv_driver_t *) this_gen;
+ xv_frame_t *frame = (xv_frame_t *) frame_gen;
+ unsigned int xv_format;
+
+ if ((frame->width != width) || (frame->height != height) || (frame->format != format)) {
+
+ XLockDisplay (this->display);
+
+ /*
+ * (re-) allocate xvimage
+ */
+
+ if (frame->image) {
+ XShmDetach (this->display, &frame->shminfo);
+
+ XFree (frame->image);
+ shmdt (frame->shminfo.shmaddr);
+ shmctl (frame->shminfo.shmid, IPC_RMID,NULL);
+
+ frame->image = NULL;
+ }
+
+ switch (format) {
+ case IMGFMT_YV12:
+ xv_format = this->xv_format_yv12;
+ break;
+ case IMGFMT_RGB:
+ xv_format = this->xv_format_rgb;
+ break;
+ case IMGFMT_YUY2:
+ xv_format = this->xv_format_yuy2;
+ break;
+ default:
+ fprintf (stderr, "xv_update_frame_format: unknown format %08x\n",format);
+ exit (1);
+ }
+
+ frame->image = XvShmCreateImage(this->display, this->xv_port, xv_format, 0,
+ width, height, &frame->shminfo);
+
+ if (frame->image == NULL ) {
+ fprintf(stderr, "xv_image_format: XvShmCreateImage failed.\n");
+ exit (1);
+ }
+
+ frame->shminfo.shmid=shmget(IPC_PRIVATE,
+ frame->image->data_size,
+ IPC_CREAT | 0777);
+
+ if (frame->image->data_size==0) {
+ fprintf(stderr, "xv_update_frame_format: XvShmCreateImage returned a zero size\n");
+ exit (1);
+ }
+
+ if (frame->shminfo.shmid < 0 ) {
+ perror("xv_update_frame_format: shared memory error in shmget: ");
+ exit (1);
+ }
+
+ frame->shminfo.shmaddr = (char *) shmat(frame->shminfo.shmid, 0, 0);
+
+ if (frame->shminfo.shmaddr == NULL) {
+ fprintf(stderr, "xv_update_frame_format: shared memory error (address error NULL)\n");
+ exit (1);
+ }
+
+ if (frame->shminfo.shmaddr == ((char *) -1)) {
+ fprintf(stderr, "xv_update_frame_format: shared memory error (address error)\n");
+ exit (1);
+ }
+
+ frame->shminfo.readOnly = False;
+ frame->image->data = frame->shminfo.shmaddr;
+
+ XShmAttach(this->display, &frame->shminfo);
+
+ XSync(this->display, False);
+ shmctl(frame->shminfo.shmid, IPC_RMID, 0);
+
+ frame->vo_frame.base[0] = frame->image->data;
+ frame->vo_frame.base[1] = frame->image->data + width * height * 5 / 4;
+ frame->vo_frame.base[2] = frame->image->data + width * height;
+
+ frame->width = width;
+ frame->height = height;
+ frame->format = format;
+
+ XUnlockDisplay (this->display);
+ }
+
+ frame->ratio_code = ratio_code;
+}
+
+static void xv_calc_format (xv_driver_t *this, int width, int height, int ratio_code) {
+
+ double image_ratio, desired_ratio;
+
+ this->delivered_width = width;
+ this->delivered_height = height;
+ this->delivered_ratio_code = ratio_code;
+
+ /*
+ * aspect ratio calculation
+ */
+
+ image_ratio = (double) this->delivered_width / (double) this->delivered_height;
+
+ xprintf (VERBOSE | VIDEO, "display_ratio : %f\n",this->display_ratio);
+ xprintf (VERBOSE | VIDEO, "stream aspect ratio : %f , code : %d\n", image_ratio, ratio_code);
+
+ switch (this->props[VO_PROP_ASPECT_RATIO].value) {
+ case ASPECT_AUTO:
+ switch (ratio_code) {
+ case 3: /* anamorphic */
+ desired_ratio = 16.0 /9.0;
+ break;
+ case 42: /* probably non-mpeg stream => don't touch aspect ratio */
+ desired_ratio = image_ratio;
+ break;
+ case 0: /* forbidden */
+ fprintf (stderr, "invalid ratio, using 4:3\n");
+ case 1: /* "square" => 4:3 */
+ case 2: /* 4:3 */
+ default:
+ xprintf (VIDEO, "unknown aspect ratio (%d) in stream => using 4:3\n", ratio_code);
+ desired_ratio = 4.0 / 3.0;
+ break;
+ }
+ break;
+ case ASPECT_ANAMORPHIC:
+ desired_ratio = 16.0 / 9.0;
+ break;
+ case ASPECT_DVB:
+ desired_ratio = 2.0 / 1.0;
+ break;
+ default:
+ desired_ratio = 4.0 / 3.0;
+ }
+
+ /* this->ratio_factor = display_ratio * desired_ratio / image_ratio ; */
+ this->ratio_factor = this->display_ratio * desired_ratio;
+
+
+ /*
+ * calc output frame size
+ */
+
+ if (this->props[VO_PROP_FULLSCREEN].value) {
+
+ if ( ((double) this->fullscreen_width / this->ratio_factor) < this->fullscreen_height ) {
+
+ this->output_width = this->fullscreen_width ;
+ this->output_height = (double) this->fullscreen_width / this->ratio_factor ;
+ this->output_xoffset = 0;
+ this->output_yoffset = (this->fullscreen_height - this->output_height) / 2;
+
+ } else {
+
+ this->output_width = (double) this->fullscreen_height * this->ratio_factor ;
+ this->output_height = this->fullscreen_height;
+ this->output_xoffset = (this->fullscreen_width - this->output_width) / 2;
+ this->output_yoffset = 0;
+ }
+
+ } else {
+
+ double corr_factor = this->ratio_factor / image_ratio ;
+
+
+ if (corr_factor >= 1.0) {
+ this->output_width = this->delivered_width * corr_factor;
+ this->output_height = this->delivered_height ;
+ }
+ else {
+ this->output_width = this->delivered_width;
+ this->output_height = this->delivered_height / corr_factor;
+ }
+
+ /* little hack to zoom mpeg1 / other small streams by default*/
+ if (this->output_width<600) {
+ this->output_width *=2;
+ this->output_height *=2;
+ }
+
+ this->output_xoffset = 0;
+ this->output_yoffset = 0;
+ }
+}
+
+typedef struct
+{
+ int flags;
+ int functions;
+ int decorations;
+ int input_mode;
+ int status;
+} MWMHints;
+
+#define MWM_HINTS_DECORATIONS (1L << 1)
+#define PROP_MWM_HINTS_ELEMENTS 5
+
+static void xv_setup_window (xv_driver_t *this) {
+
+ static char *window_title = "xine Xv video output";
+ XSizeHints hint;
+ XWMHints *wm_hint;
+ XSetWindowAttributes attr;
+ Atom prop;
+ Atom wm_delete_window;
+ MWMHints mwmhints;
+ XEvent xev;
+ XGCValues xgcv;
+
+ XLockDisplay (this->display);
+
+ if (this->props[VO_PROP_FULLSCREEN].value) {
+
+ if (this->window) {
+
+ if (this->in_fullscreen) {
+ XUnlockDisplay (this->display);
+ return;
+ }
+
+ XDestroyWindow(this->display, this->window);
+ this->window = 0;
+
+ }
+
+ this->in_fullscreen = 1;
+
+ /*
+ * open fullscreen window
+ */
+
+ attr.background_pixel = this->black.pixel;
+
+ this->window = XCreateWindow (this->display, RootWindow (this->display, this->screen),
+ 0, 0, this->fullscreen_width, this->fullscreen_height,
+ 0, this->depth, CopyFromParent, this->vinfo.visual,
+ CWBackPixel, &attr);
+
+ if (this->xclasshint != NULL)
+ XSetClassHint(this->display, this->window, this->xclasshint);
+
+ /*
+ * wm, no borders please
+ */
+
+ prop = XInternAtom(this->display, "_MOTIF_WM_HINTS", False);
+ mwmhints.flags = MWM_HINTS_DECORATIONS;
+ mwmhints.decorations = 0;
+ XChangeProperty(this->display, this->window, prop, prop, 32,
+ PropModeReplace, (unsigned char *) &mwmhints,
+ PROP_MWM_HINTS_ELEMENTS);
+ XSetTransientForHint(this->display, this->window, None);
+ XRaiseWindow(this->display, this->window);
+
+ } else {
+
+ if (this->window) {
+
+ if (this->in_fullscreen) {
+ XDestroyWindow(this->display, this->window);
+ this->window = 0;
+ } else {
+
+ XResizeWindow (this->display, this->window,
+ this->output_width, this->output_height);
+
+ XUnlockDisplay (this->display);
+
+ return;
+
+ }
+ }
+
+ this->in_fullscreen = 0;
+
+ hint.x = 0;
+ hint.y = 0;
+ hint.width = this->output_width;
+ hint.height = this->output_height;
+ hint.flags = PPosition | PSize;
+
+ /*
+ theCmap = XCreateColormap(gDisplay, RootWindow(gDisplay,gXv.screen),
+ gXv.vinfo.visual, AllocNone); */
+
+ attr.background_pixel = this->black.pixel;
+ attr.border_pixel = 1;
+ /* attr.colormap = theCmap; */
+
+
+ this->window = XCreateWindow(this->display, RootWindow(this->display, this->screen),
+ hint.x, hint.y, hint.width, hint.height, 4,
+ this->depth, CopyFromParent, this->vinfo.visual,
+ CWBackPixel | CWBorderPixel , &attr);
+
+ if (this->xclasshint != NULL)
+ XSetClassHint(this->display, this->window, this->xclasshint);
+
+
+ /* Tell other applications about this window */
+
+ XSetStandardProperties(this->display, this->window, window_title, window_title,
+ None, NULL, 0, &hint);
+
+ }
+
+ XSelectInput(this->display, this->window, StructureNotifyMask | ExposureMask | KeyPressMask | ButtonPressMask);
+
+ wm_hint = XAllocWMHints();
+ if (wm_hint != NULL) {
+ wm_hint->input = True;
+ wm_hint->initial_state = NormalState;
+ wm_hint->flags = InputHint | StateHint;
+ XSetWMHints(this->display, this->window, wm_hint);
+ XFree(wm_hint);
+ }
+
+ wm_delete_window = XInternAtom(this->display, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(this->display, this->window, &wm_delete_window, 1);
+
+ /* Map window. */
+
+ XMapRaised(this->display, this->window);
+
+ /* Wait for map. */
+
+ do {
+ XMaskEvent(this->display,
+ StructureNotifyMask,
+ &xev) ;
+ } while (xev.type != MapNotify || xev.xmap.event != this->window);
+
+ XFlush(this->display);
+ XSync(this->display, False);
+
+ this->gc = XCreateGC(this->display, this->window, 0L, &xgcv);
+
+ if (this->in_fullscreen) {
+ XSetInputFocus (this->display, this->window, RevertToNone, CurrentTime);
+ XMoveWindow (this->display, this->window, 0, 0);
+ }
+
+ XUnlockDisplay (this->display);
+
+ /* drag and drop FIXME: move this to the GUI */
+
+ /*
+ if(!gXv.xdnd)
+ gXv.xdnd = (DND_struct_t *) malloc(sizeof(DND_struct_t));
+
+ gui_init_dnd(gXv.xdnd);
+ gui_dnd_set_callback (gXv.xdnd, gui_dndcallback);
+ gui_make_window_dnd_aware (gXv.xdnd, gXv.window);
+ */
+
+ /*
+ * make cursor disappear
+ */
+
+ /* FIXME: implement in a clean way
+
+ Cursor not already created.
+ if(gXv.current_cursor == -1) {
+ create_cursor_xv(theCmap);
+ gXv.current_cursor = SHOW_CURSOR;
+ };
+ */
+}
+
+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;
+
+ if ( (frame->width != this->delivered_width) || (frame->height != this->delivered_height)
+ || (frame->ratio_code != this->delivered_ratio_code) ) {
+
+ xv_calc_format (this, frame->width, frame->height, frame->ratio_code);
+ xv_setup_window (this);
+ }
+
+ XLockDisplay (this->display);
+
+ XvShmPutImage(this->display, this->xv_port, this->window, this->gc, frame->image,
+ 0, 0, frame->width, frame->height,
+ this->output_xoffset, this->output_yoffset,
+ this->output_width, this->output_height, False);
+
+
+ XFlush(this->display);
+
+ XUnlockDisplay (this->display);
+
+ /* FIXME: this should be done using the completion event */
+ if (this->cur_frame) {
+ this->cur_frame->vo_frame.displayed (&this->cur_frame->vo_frame);
+ }
+
+ this->cur_frame = frame;
+}
+
+static int xv_get_property (vo_driver_t *this_gen, int property) {
+
+ xv_driver_t *this = (xv_driver_t *) this_gen;
+
+ return this->props[property].value;
+
+}
+
+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) {
+ XvSetPortAttribute (this->display, this->xv_port,
+ this->props[property].atom, value);
+ XvGetPortAttribute (this->display, this->xv_port,
+ this->props[property].atom,
+ &this->props[property].value);
+
+ this->config->set_int (this->config, this->props[property].key,
+ this->props[property].value);
+
+ return this->props[property].value;
+ } else {
+ /* FIXME: implement these props
+ switch (property) {
+ case VO_PROP_WINDOW_VISIBLE:
+ break;
+ case VO_PROP_CURSOR_VISIBLE:
+ break;
+ case VO_PROP_FULLSCREEN:
+ break;
+ case VO_PROP_INTERLACED:
+ break;
+ case VO_PROP_ASPECT_RATIO:
+ 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 void xv_handle_event (vo_driver_t *this_gen, void *event_gen) {
+
+ /* FIXME: implement */
+
+}
+
+static void* xv_get_window (vo_driver_t *this_gen) {
+ xv_driver_t *this = (xv_driver_t *) this_gen;
+
+ return &this->window;
+}
+
+static void xv_set_logo_mode (vo_driver_t *this_gen, int show_logo) {
+
+ /* FIXME: implement */
+}
+
+static void xv_exit (vo_driver_t *this_gen) {
+
+ xv_driver_t *this = (xv_driver_t *) this_gen;
+
+ if(XvUngrabPort (this->display, this->xv_port, CurrentTime) != Success) {
+ fprintf(stderr, "xv_exit: XvUngrabPort() failed.\n");
+ }
+}
+
+static int xv_check_yv12 (Display *display, XvPortID port)
+{
+ XvImageFormatValues * formatValues;
+ int formats;
+ int i;
+
+ formatValues = XvListImageFormats (display, port, &formats);
+ for (i = 0; i < formats; i++)
+ if ((formatValues[i].id == IMGFMT_YV12) &&
+ (! (strcmp (formatValues[i].guid, "YV12")))) {
+ XFree (formatValues);
+ return 0;
+ }
+ XFree (formatValues);
+ return 1;
+}
+
+static void xv_check_capability (xv_driver_t *this, uint32_t capability, int property,
+ XvAttribute attr, int base_id, char *str_prop) {
+
+ int nDefault;
+
+ this->capabilities |= capability;
+ this->props[property].min = attr.min_value;
+ this->props[property].max = attr.max_value;
+ this->props[property].atom = XInternAtom (this->display, str_prop, False);
+ this->props[property].key = str_prop;
+
+ XvGetPortAttribute (this->display, this->xv_port, this->props[property].atom, &nDefault);
+
+ xv_set_property (&this->vo_driver, property, this->config->lookup_int (this->config, str_prop, nDefault) );
+}
+
+vo_driver_t *init_video_out_xv (Display *display, config_values_t *config) {
+
+ xv_driver_t *this;
+ unsigned int adaptor_num, adaptors, i, j, formats;
+ unsigned int ver,rel,req,ev,err;
+ unsigned int xv_port;
+ XvAttribute *attr;
+ XvAdaptorInfo *adaptor_info;
+ XvImageFormatValues *fo;
+ int nattr;
+ double res_h, res_v;
+ XColor ignored;
+ XWindowAttributes attribs;
+ int dummy_a, dummy_b;
+#ifdef HAVE_XINERAMA
+ int screens;
+ XineramaScreenInfo *screeninfo = NULL;
+#endif
+
+ /*
+ * check for Xvideo support
+ */
+
+ if (Success != XvQueryExtension(display,&ver,&rel,&req,&ev,&err)) {
+ printf ("video_out_xv: Xv extension not present.\n");
+ return NULL;
+ }
+
+ /*
+ * check adaptors, search for one that supports (at least) yuv12
+ */
+
+ if (Success != XvQueryAdaptors(display,DefaultRootWindow(display),
+ &adaptors,&adaptor_info)) {
+ printf("video_out_xv: XvQueryAdaptors failed.\n");
+ return NULL;
+ }
+
+ xv_port = 0;
+ adaptor_num = 0;
+
+ while ( (adaptor_num < adaptors) && !xv_port) {
+ if (adaptor_info[adaptor_num].type & XvImageMask)
+ for (j = 0; j < adaptor_info[adaptor_num].num_ports; j++)
+ if (( !(xv_check_yv12 (display, adaptor_info[adaptor_num].base_id + j)))
+ && (XvGrabPort (display, adaptor_info[adaptor_num].base_id + j, 0) == Success)) {
+ xv_port = adaptor_info[adaptor_num].base_id + j;
+ break;
+ }
+
+ adaptor_num++;
+ }
+
+ if (!xv_port) {
+ printf ("video_out_xv: Xv extension is present but I couldn't find a usable yuv12 port.\n");
+ printf (" Looks like your graphics hardware driver doesn't support Xv?!\n");
+ XvFreeAdaptorInfo (adaptor_info);
+ return NULL;
+ } else
+ printf ("video_out_xv: using Xv port %d for hardware colorspace conversion and scaling.\n", xv_port);
+
+
+ /*
+ * from this point on, nothing should go wrong anymore; so let's start initializing this driver
+ */
+
+ this = malloc (sizeof (xv_driver_t));
+ memset (this, 0, sizeof(xv_driver_t));
+
+ this->display = display;
+ this->screen = DefaultScreen(display);
+ this->xv_port = xv_port;
+ this->capabilities = 0;
+ this->config = config;
+
+ 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.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.handle_event = xv_handle_event;
+ this->vo_driver.get_window = xv_get_window;
+ this->vo_driver.set_logo_mode = xv_set_logo_mode;
+ this->vo_driver.exit = xv_exit;
+
+ if (XAllocNamedColor (display, DefaultColormap (display, this->screen),
+ "black", &this->black, &ignored) == 0) {
+ fprintf (stderr, "video_out_xv: cannot allocate color black\n");
+ exit(1);
+ }
+
+ XGetWindowAttributes(display, DefaultRootWindow(display), &attribs);
+
+ this->depth = attribs.depth;
+
+ if (this->depth != 15 && this->depth != 16 && this->depth != 24 && this->depth != 32) {
+ /* The root window may be 8bit but there might still be
+ * visuals with other bit depths. For example this is the
+ * case on Sun/Solaris machines.
+ */
+ this->depth = 24;
+ }
+
+ XMatchVisualInfo(display, this->screen, this->depth, TrueColor, &this->vinfo);
+
+ /*
+ * 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 = 0;
+ }
+
+ this->props[VO_PROP_WINDOW_VISIBLE].value = 1;
+ this->props[VO_PROP_CURSOR_VISIBLE].value = 1;
+ this->props[VO_PROP_FULLSCREEN].value = 0;
+ this->props[VO_PROP_INTERLACED].value = 0;
+ this->props[VO_PROP_ASPECT_RATIO].value = ASPECT_AUTO;
+
+ /*
+ * check this adaptor's capabilities
+ */
+
+ attr = XvQueryPortAttributes(display, adaptor_info[i].base_id, &nattr);
+ if(attr && nattr) {
+ int k;
+
+ for(k = 0; k < nattr; k++) {
+
+ if(attr[k].flags & XvSettable) {
+ if(!strcmp(attr[k].name, "XV_HUE"))
+ xv_check_capability (this, VO_CAP_HUE, VO_PROP_HUE, attr[k],
+ adaptor_info[i].base_id, "XV_HUE");
+ else if(!strcmp(attr[k].name, "XV_SATURATION"))
+ xv_check_capability (this, VO_CAP_SATURATION, VO_PROP_SATURATION, attr[k],
+ adaptor_info[i].base_id, "XV_SATURATION");
+ else if(!strcmp(attr[k].name, "XV_BRIGHTNESS"))
+ xv_check_capability (this, VO_CAP_BRIGHTNESS, VO_PROP_BRIGHTNESS, attr[k],
+ adaptor_info[i].base_id, "XV_BRIGHTNESS");
+ else if(!strcmp(attr[k].name, "XV_CONTRAST"))
+ xv_check_capability (this, VO_CAP_CONTRAST, VO_PROP_CONTRAST, attr[k],
+ adaptor_info[i].base_id, "XV_CONTRAST");
+ else if(!strcmp(attr[k].name, "XV_COLORKEY"))
+ xv_check_capability (this, VO_CAP_COLORKEY, VO_PROP_COLORKEY, attr[k],
+ adaptor_info[i].base_id, "XV_COLORKEY");
+ }
+
+ XFree(attr);
+ }
+ } else {
+ printf("video_out_xv: no port attributes defined.\n");
+ }
+
+ XvFreeAdaptorInfo (adaptor_info);
+
+ /*
+ * check supported image formats
+ */
+
+ fo = XvListImageFormats(display, this->xv_port, (int*)&formats);
+
+ this->xv_format_yv12 = 0;
+ this->xv_format_yuy2 = 0;
+ this->xv_format_rgb = 0;
+
+ for(i = 0; i < formats; i++) {
+ xprintf(VERBOSE|VIDEO, "video_out_xv: Xv image format: 0x%x (%4.4s) %s\n",
+ fo[i].id, (char*)&fo[i].id,
+ (fo[i].format == XvPacked) ? "packed" : "planar");
+ if (fo[i].id == IMGFMT_YV12) {
+ this->xv_format_yv12 = fo[i].id;
+ this->capabilities |= VO_CAP_YV12;
+ printf ("video_out_xv: this adaptor supports the yv12 format.\n");
+ } else if (fo[i].id == IMGFMT_YUY2) {
+ this->xv_format_yuy2 = fo[i].id;
+ this->capabilities |= VO_CAP_YUY2;
+ printf ("video_out_xv: this adaptor supports the yuy2 format.\n");
+ } else if (fo[i].id == IMGFMT_RGB) {
+ this->xv_format_rgb = fo[i].id;
+ this->capabilities |= VO_CAP_RGB;
+ printf ("video_out_xv: this adaptor supports the rgb format.\n");
+ }
+ }
+
+ /*
+ * find out screen dimensions
+ */
+
+#ifdef HAVE_XINERAMA
+ /* Spark
+ * some Xinerama stuff
+ * I want to figure out what fullscreen means for this setup
+ */
+
+ if ((XineramaQueryExtension (display, &dummy_a, &dummy_b))
+ && (screeninfo = XineramaQueryScreens(display, &screens))) {
+ /* Xinerama Detected */
+ xprintf (VERBOSE|VIDEO,
+ "Display is using Xinerama with %d screens\n", screens);
+ xprintf (VERBOSE|VIDEO,
+ " going to assume we are using the first screen.\n");
+ xprintf (VERBOSE|VIDEO, " size of the first screen is %dx%d.\n",
+ screeninfo[0].width, screeninfo[0].height);
+
+ if (XineramaIsActive(display)) {
+ this->fullscreen_width = screeninfo[0].width;
+ this->fullscreen_height = screeninfo[0].height;
+ } else {
+ this->fullscreen_width = DisplayWidth (display, this->screen);
+ this->fullscreen_height = DisplayHeight (display, this->screen);
+ }
+
+ } else {
+ /* no Xinerama */
+ xprintf (VERBOSE|VIDEO, "Display is not using Xinerama.\n");
+ }
+#else
+ this->fullscreen_width = DisplayWidth (display, this->screen);
+ this->fullscreen_height = DisplayHeight (display, this->screen);
+#endif
+
+ res_h = (this->fullscreen_width*1000 / DisplayWidthMM (display, this->screen));
+ res_v = (this->fullscreen_height*1000 / DisplayHeightMM (display, this->screen));
+ this->display_ratio = res_h / res_v;
+
+ /*
+ * init window
+ */
+
+ xv_calc_format (this, 720, 576, 2);
+ xv_setup_window (this);
+
+ return &this->vo_driver;
+}
+
+#endif