David Reveman
Wed, 11 Jul 2007 16:13:39 -0700
I had to update the video plugin interface slightly to fix some bugs. I've attached an updated mplayer patch. -David
--- libvo/vo_xv.c (revision 22417)
+++ libvo/vo_xv.c (working copy)
@@ -92,6 +92,520 @@
static uint32_t dwidth, dheight;
static uint32_t max_width = 0, max_height = 0; // zero means: not set
+#include "libswscale/swscale.h"
+#include <X11/Xatom.h>
+
+#define GRAVITY_WEST (1 << 0)
+#define GRAVITY_EAST (1 << 1)
+#define GRAVITY_NORTH (1 << 2)
+#define GRAVITY_SOUTH (1 << 3)
+
+#define COMPIZ_IMAGE_FORMAT_RGB (1 << 0)
+#define COMPIZ_IMAGE_FORMAT_YV12 (1 << 1)
+
+static Atom vo_supporting_wm_check_atom;
+static Atom vo_compiz_video_atom;
+static Atom vo_compiz_video_supported_atom;
+static Atom vo_compiz_video_image_format_rgb_atom;
+static Atom vo_compiz_video_image_format_yv12_atom;
+static int vo_compiz_formats = 0;
+static int vo_compiz_format = 0;
+static Pixmap vo_pixmap = None;
+static GC vo_pixmap_gc = None;
+static Atom vo_xprop = None;
+static XImage *ximage = NULL;
+static XShmSegmentInfo compizShminfo;
+static int pixmap_width;
+static int pixmap_height;
+static int pixmap_height;
+static int pixmap_depth;
+static int pixmap_offsets[3];
+static int pixmap_pitches[3];
+static struct SwsContext *swsContext = NULL;
+static Window wm_check_window = None;
+
+static int x11_get_property (Atom type, Atom **args, unsigned long *nitems)
+{
+ int format;
+ unsigned long bytesafter;
+
+ return (Success ==
+ XGetWindowProperty(mDisplay, mRootWin, type, 0, 16384, False,
+ AnyPropertyType, &type, &format, nitems,
+ &bytesafter, (unsigned char **) args)
+ && *nitems > 0);
+}
+
+static int error_handler (Display *dpy, XErrorEvent *e)
+{
+ return 0;
+}
+
+static Bool x11_update_wm_check_window (void)
+{
+ Atom actual;
+ int result, format;
+ unsigned long n, left;
+ unsigned char *data;
+
+ result = XGetWindowProperty (mDisplay, mRootWin,
+ vo_supporting_wm_check_atom,
+ 0L, 1L, False, XA_WINDOW, &actual, &format,
+ &n, &left, &data);
+
+ if (result == Success && n && data)
+ {
+ XErrorHandler old;
+ Window win, root;
+ unsigned int ui;
+ int i;
+
+ memcpy (&win, data, sizeof (Window));
+ XFree ((void *) data);
+
+ old = XSetErrorHandler (error_handler);
+
+ XSelectInput (mDisplay, win, StructureNotifyMask);
+
+ if (!XGetGeometry (mDisplay, win, &root, &i, &i, &ui, &ui, &ui, &ui))
+ win = None;
+
+ XSetErrorHandler (old);
+
+ wm_check_window = win;
+ if (wm_check_window)
+ return True;
+ }
+
+ return False;
+}
+
+static void vo_compiz_detect (void)
+{
+ unsigned long nitems;
+ Atom *args = NULL;
+ int formats = 0;
+ int i;
+
+ if (!x11_update_wm_check_window ())
+ {
+ vo_compiz_formats = 0;
+ return;
+ }
+
+ if (x11_get_property (vo_compiz_video_supported_atom, &args, &nitems))
+ {
+ mp_msg (MSGT_VO, MSGL_V, "[xv] Detected wm supports compiz video.\n");
+
+ for (i = 0; i < nitems; i++)
+ {
+ if (args[i] == vo_compiz_video_image_format_rgb_atom)
+ formats |= COMPIZ_IMAGE_FORMAT_RGB;
+ else if (args[i] == vo_compiz_video_image_format_yv12_atom)
+ formats |= COMPIZ_IMAGE_FORMAT_YV12;
+ }
+
+ XFree (args);
+ }
+
+ vo_compiz_formats = formats;
+}
+
+static void vo_compiz_init (void)
+{
+ vo_supporting_wm_check_atom =
+ XInternAtom (mDisplay, "_NET_SUPPORTING_WM_CHECK", False);
+
+ vo_compiz_video_atom = XInternAtom (mDisplay,
+ "_COMPIZ_VIDEO",
+ False);
+
+ vo_compiz_video_supported_atom = XInternAtom (mDisplay,
+ "_COMPIZ_VIDEO_SUPPORTED",
+ False);
+
+ vo_compiz_video_image_format_rgb_atom =
+ XInternAtom (mDisplay,
+ "_COMPIZ_VIDEO_IMAGE_FORMAT_RGB",
+ False);
+
+ vo_compiz_video_image_format_yv12_atom =
+ XInternAtom (mDisplay,
+ "_COMPIZ_VIDEO_IMAGE_FORMAT_YV12",
+ False);
+
+ XSelectInput (mDisplay, mRootWin, PropertyChangeMask);
+
+ vo_compiz_detect ();
+}
+
+static void allocate_ximage (void)
+{
+#ifdef HAVE_SHM
+ if (Shmem_Flag)
+ {
+ ximage =
+ XShmCreateImage (mDisplay, NULL, pixmap_depth, ZPixmap, NULL,
+ &compizShminfo, pixmap_width, pixmap_height);
+ compizShminfo.shmid = shmget (IPC_PRIVATE,
+ ximage->bytes_per_line *
+ ximage->height, IPC_CREAT | 0777);
+ compizShminfo.shmaddr = (char *) shmat (compizShminfo.shmid, 0, 0);
+ compizShminfo.readOnly = False;
+
+ ximage->data = compizShminfo.shmaddr;
+ XShmAttach (mDisplay, &compizShminfo);
+ XSync (mDisplay, False);
+ shmctl (compizShminfo.shmid, IPC_RMID, 0);
+ } else
+#endif
+ {
+ ximage =
+ XShmCreateImage (mDisplay, NULL, pixmap_depth, ZPixmap, NULL,
+ &compizShminfo, pixmap_width, pixmap_height);
+ ximage->data = malloc (ximage->bytes_per_line *
+ ximage->height);
+ XSync (mDisplay, False);
+ }
+
+ memset (ximage->data, 128, ximage->bytes_per_line * ximage->height);
+}
+
+static void deallocate_ximage (void)
+{
+#ifdef HAVE_SHM
+ if (Shmem_Flag)
+ {
+ XShmDetach (mDisplay, &compizShminfo);
+ shmdt (compizShminfo.shmaddr);
+ } else
+#endif
+ {
+ free (ximage->data);
+ }
+
+ XFree (ximage);
+ XSync (mDisplay, False);
+}
+
+static void vo_compiz_put_ximage (XImage *myximage)
+{
+
+#ifdef HAVE_SHM
+ if (Shmem_Flag)
+ {
+ XShmPutImage (mDisplay, vo_pixmap, vo_pixmap_gc, myximage,
+ 0, 0,
+ 0, 0,
+ myximage->width, myximage->height,
+ True);
+ } else
+#endif
+ {
+ XPutImage (mDisplay, vo_pixmap, vo_pixmap_gc, myximage,
+ 0, 0,
+ 0, 0,
+ myximage->width, myximage->height);
+ }
+
+ if (!vo_xprop)
+ {
+ long data[11];
+ int w, h;
+
+ data[0] = vo_pixmap;
+
+ if (vo_compiz_format == COMPIZ_IMAGE_FORMAT_YV12)
+ data[1] = vo_compiz_video_image_format_yv12_atom;
+ else
+ data[1] = vo_compiz_video_image_format_rgb_atom;
+
+ data[2] = image_width;
+ data[3] = image_height;
+
+ aspect (&w, &h, A_NOZOOM);
+
+ data[4] = w;
+ data[5] = h;
+ data[6] = vo_panscan * 65536;
+
+ data[7] = GRAVITY_NORTH | GRAVITY_WEST;
+ data[8] = 0;
+ data[9] = 0;
+ data[10] = GRAVITY_SOUTH | GRAVITY_EAST;
+ data[11] = 0;
+ data[12] = 0;
+
+ XChangeProperty (mDisplay,
+ vo_window,
+ vo_compiz_video_atom,
+ XA_INTEGER,
+ 32, PropModeReplace, (unsigned char *) data,
+ 13);
+
+ vo_xprop = 1;
+ }
+
+ XSync (mDisplay, False);
+}
+
+static void vo_compiz_check_output (void)
+{
+ int format = 0;
+
+ if (vo_compiz_formats)
+ {
+ if (xv_format == IMGFMT_YV12)
+ format = vo_compiz_formats & COMPIZ_IMAGE_FORMAT_YV12;
+
+ if (!format)
+ format = vo_compiz_formats & COMPIZ_IMAGE_FORMAT_RGB;
+ }
+
+ if (format != vo_compiz_format)
+ {
+ if (ximage)
+ {
+ deallocate_ximage ();
+ ximage = NULL;
+ }
+
+ if (vo_pixmap)
+ {
+ XFreePixmap (mDisplay, vo_pixmap);
+ vo_pixmap = None;
+ }
+
+ if (swsContext)
+ {
+ sws_freeContext (swsContext);
+ swsContext = NULL;
+ }
+
+ vo_compiz_format = format;
+ }
+
+ if (format)
+ {
+ int width, height;
+
+ if (format == COMPIZ_IMAGE_FORMAT_YV12)
+ {
+ width = (image_width + 7) & ~7;
+ height = (image_height + 1) & ~1;
+
+ pixmap_width = width;
+ pixmap_height = height + height / 2;
+ pixmap_depth = 8;
+
+ pixmap_offsets[0] = 0;
+ pixmap_offsets[1] = width * height;
+ pixmap_offsets[2] = width * height + (width / 2);
+
+ pixmap_pitches[0] = width;
+ pixmap_pitches[1] = width;
+ pixmap_pitches[2] = width;
+
+ mp_msg (MSGT_VO, MSGL_V,
+ "[xv] using compiz composited yv12 output\n");
+ }
+ else
+ {
+ width = image_width;
+ height = image_height;
+
+ pixmap_width = width;
+ pixmap_height = height;
+ pixmap_depth = 24;
+
+ swsContext = (struct SwsContext *)
+ sws_getContextFromCmdLine (width, height, image_format,
+ width, height, IMGFMT_BGR32);
+
+ mp_msg (MSGT_VO, MSGL_V,
+ "[xv] using compiz composited rgb output\n");
+ }
+
+ vo_pixmap = XCreatePixmap (mDisplay, mRootWin,
+ pixmap_width, pixmap_height,
+ pixmap_depth);
+
+ if (vo_pixmap_gc != None)
+ XFreeGC (mDisplay, vo_pixmap_gc);
+
+ allocate_ximage ();
+
+ vo_pixmap_gc = XCreateGC (mDisplay, vo_pixmap, 0L, NULL);
+ vo_xprop = None;
+
+ XSetWindowBackground (mDisplay, vo_window, 0);
+ XClearWindow (mDisplay, vo_window);
+ }
+ else
+ {
+ XDeleteProperty (mDisplay, vo_window, vo_compiz_video_atom);
+
+ mp_msg (MSGT_VO, MSGL_V,
+ "[xv] compiz composited output not available\n");
+ }
+}
+
+static Bool check_compiz_event (Display *display, XEvent *event, XPointer arg)
+{
+ if (event->type == DestroyNotify)
+ {
+ if (event->xdestroywindow.window == wm_check_window)
+ return True;
+ }
+ else if (event->type == PropertyNotify)
+ {
+ if (event->xproperty.atom == vo_compiz_video_supported_atom)
+ return True;
+ }
+
+ return False;
+}
+
+static void vo_compiz_check_events (void)
+{
+ XEvent event;
+
+ if (XCheckIfEvent (mDisplay, &event, check_compiz_event, NULL))
+ {
+ vo_compiz_detect ();
+ vo_compiz_check_output ();
+ }
+}
+
+static int vo_compiz_draw_slice (uint8_t * image[], int stride[],
+ int w, int h, int x, int y)
+{
+ if (vo_compiz_format == COMPIZ_IMAGE_FORMAT_YV12)
+ {
+ uint8_t *dst;
+
+ dst = ximage->data + pixmap_offsets[0] + pixmap_pitches[0] * y + x;
+ memcpy_pic (dst, image[0], w, h, pixmap_pitches[0], stride[0]);
+
+ x /= 2;
+ y /= 2;
+ w /= 2;
+ h /= 2;
+
+ dst = ximage->data + pixmap_offsets[1] + pixmap_pitches[1] * y + x;
+ memcpy_pic (dst, image[2], w, h, pixmap_pitches[1], stride[2]);
+
+ dst = ximage->data + pixmap_offsets[2] + pixmap_pitches[2] * y + x;
+ memcpy_pic (dst, image[1], w, h, pixmap_pitches[2], stride[1]);
+ }
+ else
+ {
+ uint8_t *dst[3];
+ int dstStride[3];
+
+ dstStride[1] = dstStride[2] = 0;
+ dst[1] = dst[2] = NULL;
+
+ dst[0] = ximage->data;
+ dstStride[0] = ximage->bytes_per_line;
+
+ sws_scale (swsContext, image, stride, y, h, dst, dstStride);
+ }
+
+ return 0;
+}
+
+static uint32_t vo_compiz_draw_image (mp_image_t *mpi)
+{
+ if (mpi->flags & MP_IMGFLAG_DRAW_CALLBACK)
+ return VO_TRUE;
+
+ if (mpi->flags & MP_IMGFLAG_PLANAR)
+ {
+ vo_compiz_draw_slice (mpi->planes, mpi->stride, mpi->w, mpi->h, 0, 0);
+ return VO_TRUE;
+ }
+
+ return VO_FALSE;
+}
+
+static uint32_t vo_compiz_get_image (mp_image_t *mpi)
+{
+ if (mpi->imgfmt != image_format)
+ return VO_FALSE;
+
+ if (mpi->height != image_height)
+ return VO_FALSE;
+
+ if (vo_compiz_format == COMPIZ_IMAGE_FORMAT_YV12)
+ {
+ if (mpi->width * (mpi->bpp / 8) != pixmap_pitches[0])
+ return VO_FALSE;
+
+ if (!(mpi->flags & MP_IMGFLAG_PLANAR))
+ return VO_FALSE;
+
+ if (mpi->flags & MP_IMGFLAG_SWAPPED)
+ return VO_FALSE;
+
+ if (mpi->flags & (MP_IMGFLAG_ACCEPT_STRIDE | MP_IMGFLAG_ACCEPT_WIDTH))
+ {
+ mpi->planes[0] = ximage->data + pixmap_offsets[0];
+ mpi->stride[0] = pixmap_pitches[0];
+ mpi->planes[1] = ximage->data + pixmap_offsets[2];
+ mpi->stride[1] = pixmap_pitches[2];
+ mpi->planes[2] = ximage->data + pixmap_offsets[1];
+ mpi->stride[2] = pixmap_pitches[1];
+
+ mpi->width = mpi->stride[0] / (mpi->bpp / 8);
+ }
+ else
+ {
+ return VO_FALSE;
+ }
+ }
+ else
+ {
+ if (mpi->type != MP_IMGTYPE_STATIC)
+ return VO_FALSE;
+
+ if (mpi->flags & (MP_IMGFLAG_PLANAR | MP_IMGFLAG_YUV))
+ return VO_FALSE;
+
+ if (mpi->width != image_width)
+ return VO_FALSE;
+
+ mpi->stride[0] = image_width * 4;
+ mpi->planes[0] = ximage->data;
+ }
+
+ mpi->flags |= MP_IMGFLAG_DIRECT;
+
+ return VO_TRUE;
+}
+
+static void vo_compiz_draw_alpha (int x0, int y0, int w, int h,
+ unsigned char *src, unsigned char *srca,
+ int stride)
+{
+ x0 += image_width * (vo_panscan_x >> 1) / (vo_dwidth + vo_panscan_x);
+
+ if (vo_compiz_format == COMPIZ_IMAGE_FORMAT_YV12)
+ {
+ vo_draw_alpha_yv12 (w, h, src, srca, stride,
+ ximage->data +
+ pixmap_offsets[0] +
+ pixmap_pitches[0] * y0 + x0,
+ pixmap_pitches[0]);
+ }
+ else
+ {
+ vo_draw_alpha_rgb32 (w, h, src, srca, stride,
+ ximage->data + 4 * (y0 * image_width + x0),
+ 4 * image_width);
+ }
+}
+
static void (*draw_alpha_fnc) (int x0, int y0, int w, int h,
unsigned char *src, unsigned char *srca,
int stride);
@@ -452,6 +966,8 @@
}
#endif
+ vo_compiz_check_output ();
+
mp_msg(MSGT_VO, MSGL_V, "[xv] dx: %d dy: %d dw: %d dh: %d\n", drwX,
drwY, vo_dwidth, vo_dheight);
@@ -547,8 +1063,12 @@
static void check_events(void)
{
- int e = vo_x11_check_events(mDisplay);
+ int e;
+ vo_compiz_check_events ();
+
+ e = vo_x11_check_events(mDisplay);
+
if (e & VO_EVENT_RESIZE)
{
XGetGeometry(mDisplay, vo_window, &mRoot, &drwX, &drwY, &vo_dwidth,
@@ -592,6 +1112,7 @@
if ( visible_buf != -1 )
{
/* redraw the last visible buffer */
+ if (!vo_pixmap)
put_xvimage( xvimage[visible_buf] );
}
}
@@ -599,13 +1120,24 @@
static void draw_osd(void)
{
- vo_draw_text(image_width -
- image_width * vo_panscan_x / (vo_dwidth + vo_panscan_x),
- image_height, draw_alpha_fnc);
+ if (vo_pixmap)
+ vo_draw_text (image_width -
+ image_width * vo_panscan_x / (vo_dwidth + vo_panscan_x),
+ image_height, vo_compiz_draw_alpha);
+ else
+ vo_draw_text (image_width -
+ image_width * vo_panscan_x / (vo_dwidth + vo_panscan_x),
+ image_height, draw_alpha_fnc);
}
static void flip_page(void)
{
+ if (vo_pixmap)
+ {
+ vo_compiz_put_ximage (ximage);
+ return;
+ }
+
put_xvimage( xvimage[current_buf] );
/* remember the currently visible buffer */
@@ -626,6 +1158,9 @@
{
uint8_t *dst;
+ if (vo_pixmap)
+ return vo_compiz_draw_slice (image, stride, w, h, x, y);
+
dst = xvimage[current_buf]->data + xvimage[current_buf]->offsets[0] +
xvimage[current_buf]->pitches[0] * y + x;
memcpy_pic(dst, image[0], w, h, xvimage[current_buf]->pitches[0],
@@ -665,6 +1200,9 @@
static uint32_t draw_image(mp_image_t * mpi)
{
+ if (vo_pixmap)
+ return vo_compiz_draw_image (mpi);
+
if (mpi->flags & MP_IMGFLAG_DIRECT)
{
// direct rendering:
@@ -694,6 +1232,9 @@
{
int buf = current_buf; // we shouldn't change current_buf unless we do DR!
+ if (vo_pixmap)
+ return vo_compiz_get_image (mpi);
+
if (mpi->type == MP_IMGTYPE_STATIC && num_buffers > 1)
return VO_FALSE; // it is not static
if (mpi->imgfmt != image_format)
@@ -913,6 +1454,8 @@
fo = XvListImageFormats(mDisplay, xv_port, (int *) &formats);
+ vo_compiz_init ();
+
return 0;
}
@@ -940,7 +1483,12 @@
vo_x11_fullscreen();
/* indended, fallthrough to update panscan on fullscreen/windowed switch */
case VOCTRL_SET_PANSCAN:
- if ((vo_fs && (vo_panscan != vo_panscan_amount))
+ if (vo_pixmap)
+ {
+ panscan_calc ();
+ vo_xprop = None;
+ }
+ else if ((vo_fs && (vo_panscan != vo_panscan_amount))
|| (!vo_fs && vo_panscan_amount))
{
int old_y = vo_panscan_y;
_______________________________________________ compiz mailing list compiz@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/compiz