976 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			976 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * Xephyr - A kdrive X server thats runs in a host X window.
 | |
|  *          Authored by Matthew Allum <mallum@openedhand.com>
 | |
|  * 
 | |
|  * Copyright © 2007 OpenedHand Ltd 
 | |
|  *
 | |
|  * Permission to use, copy, modify, distribute, and sell this software and its
 | |
|  * documentation for any purpose is hereby granted without fee, provided that
 | |
|  * the above copyright notice appear in all copies and that both that
 | |
|  * copyright notice and this permission notice appear in supporting
 | |
|  * documentation, and that the name of OpenedHand Ltd not be used in
 | |
|  * advertising or publicity pertaining to distribution of the software without
 | |
|  * specific, written prior permission. OpenedHand Ltd makes no
 | |
|  * representations about the suitability of this software for any purpose.  It
 | |
|  * is provided "as is" without express or implied warranty.
 | |
|  *
 | |
|  * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | |
|  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | |
|  * EVENT SHALL OpenedHand Ltd BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 | |
|  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | |
|  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | |
|  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 | |
|  * PERFORMANCE OF THIS SOFTWARE.
 | |
|  *
 | |
|  * Authors:
 | |
|  *    Dodji Seketeli <dodji@openedhand.com>
 | |
|  */
 | |
| #ifdef HAVE_CONFIG_H
 | |
| #include <kdrive-config.h>
 | |
| #endif
 | |
| /*
 | |
|  * including some server headers (like kdrive-config.h)
 | |
|  * might define the macro _XSERVER64
 | |
|  * on 64 bits machines. That macro must _NOT_ be defined for Xlib
 | |
|  * client code, otherwise bad things happen.
 | |
|  * So let's undef that macro if necessary.
 | |
|  */
 | |
| #ifdef _XSERVER64
 | |
| #undef _XSERVER64
 | |
| #endif
 | |
| #include <X11/Xutil.h>
 | |
| #include <X11/Xlibint.h>
 | |
| #include <X11/extensions/Xvlib.h>
 | |
| #include <X11/extensions/Xvproto.h>
 | |
| #include <X11/extensions/Xext.h>
 | |
| #include <X11/extensions/extutil.h>
 | |
| #define _HAVE_XALLOC_DECLS
 | |
| 
 | |
| #include "hostx.h"
 | |
| #include "ephyrhostvideo.h"
 | |
| #include "ephyrlog.h"
 | |
| 
 | |
| #ifndef TRUE
 | |
| #define TRUE 1
 | |
| #endif /*TRUE*/
 | |
| #ifndef FALSE
 | |
| #define FALSE 0
 | |
| #endif /*FALSE*/
 | |
| static XExtensionInfo _xv_info_data;
 | |
| static XExtensionInfo *xv_info = &_xv_info_data;
 | |
| static char *xv_extension_name = XvName;
 | |
| static char *xv_error_string(Display * dpy, int code, XExtCodes * codes,
 | |
|                              char *buf, int n);
 | |
| static int xv_close_display(Display * dpy, XExtCodes * codes);
 | |
| static Bool xv_wire_to_event(Display * dpy, XEvent * host, xEvent *wire);
 | |
| 
 | |
| static XExtensionHooks xv_extension_hooks = {
 | |
|     NULL,                       /* create_gc */
 | |
|     NULL,                       /* copy_gc */
 | |
|     NULL,                       /* flush_gc */
 | |
|     NULL,                       /* free_gc */
 | |
|     NULL,                       /* create_font */
 | |
|     NULL,                       /* free_font */
 | |
|     xv_close_display,           /* close_display */
 | |
|     xv_wire_to_event,           /* wire_to_event */
 | |
|     NULL,                       /* event_to_wire */
 | |
|     NULL,                       /* error */
 | |
|     xv_error_string             /* error_string */
 | |
| };
 | |
| 
 | |
| static char *xv_error_list[] = {
 | |
|     "BadPort",                  /* XvBadPort     */
 | |
|     "BadEncoding",              /* XvBadEncoding */
 | |
|     "BadControl"                /* XvBadControl  */
 | |
| };
 | |
| 
 | |
| #define XvCheckExtension(dpy, i, val) \
 | |
|   XextCheckExtension(dpy, i, xv_extension_name, val)
 | |
| #define XvGetReq(name, req) \
 | |
|         WORD64ALIGN\
 | |
|         if ((dpy->bufptr + SIZEOF(xv##name##Req)) > dpy->bufmax)\
 | |
|                 _XFlush(dpy);\
 | |
|         req = (xv##name##Req *)(dpy->last_req = dpy->bufptr);\
 | |
|         req->reqType = info->codes->major_opcode;\
 | |
|         req->xvReqType = xv_##name; \
 | |
|         req->length = (SIZEOF(xv##name##Req))>>2;\
 | |
|         dpy->bufptr += SIZEOF(xv##name##Req);\
 | |
|         dpy->request++
 | |
| 
 | |
| static
 | |
| XEXT_GENERATE_CLOSE_DISPLAY(xv_close_display, xv_info)
 | |
| 
 | |
| static
 | |
| XEXT_GENERATE_FIND_DISPLAY(xv_find_display, xv_info,
 | |
|                            xv_extension_name,
 | |
|                            &xv_extension_hooks, XvNumEvents, NULL)
 | |
| 
 | |
| static
 | |
| XEXT_GENERATE_ERROR_STRING(xv_error_string, xv_extension_name,
 | |
|                            XvNumErrors, xv_error_list)
 | |
| 
 | |
| struct _EphyrHostXVAdaptorArray {
 | |
|     XvAdaptorInfo *adaptors;
 | |
|     unsigned int nb_adaptors;
 | |
| };
 | |
| 
 | |
| /*heavily copied from libx11*/
 | |
| #define BUFSIZE 2048
 | |
| static void
 | |
| ephyrHostXVLogXErrorEvent(Display * a_display,
 | |
|                           XErrorEvent * a_err_event, FILE * a_fp)
 | |
| {
 | |
|     char buffer[BUFSIZ];
 | |
|     char mesg[BUFSIZ];
 | |
|     char number[32];
 | |
|     const char *mtype = "XlibMessage";
 | |
|     register _XExtension *ext = (_XExtension *) NULL;
 | |
|     _XExtension *bext = (_XExtension *) NULL;
 | |
|     Display *dpy = a_display;
 | |
| 
 | |
|     XGetErrorText(dpy, a_err_event->error_code, buffer, BUFSIZ);
 | |
|     XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", mesg, BUFSIZ);
 | |
|     (void) fprintf(a_fp, "%s:  %s\n  ", mesg, buffer);
 | |
|     XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d",
 | |
|                           mesg, BUFSIZ);
 | |
|     (void) fprintf(a_fp, mesg, a_err_event->request_code);
 | |
|     if (a_err_event->request_code < 128) {
 | |
|         snprintf(number, sizeof(number), "%d", a_err_event->request_code);
 | |
|         XGetErrorDatabaseText(dpy, "XRequest", number, "", buffer, BUFSIZ);
 | |
|     }
 | |
|     else {
 | |
|         for (ext = dpy->ext_procs;
 | |
|              ext && (ext->codes.major_opcode != a_err_event->request_code);
 | |
|              ext = ext->next);
 | |
|         if (ext)
 | |
|             strcpy(buffer, ext->name);
 | |
|         else
 | |
|             buffer[0] = '\0';
 | |
|     }
 | |
|     (void) fprintf(a_fp, " (%s)\n", buffer);
 | |
|     if (a_err_event->request_code >= 128) {
 | |
|         XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d",
 | |
|                               mesg, BUFSIZ);
 | |
|         fputs("  ", a_fp);
 | |
|         (void) fprintf(a_fp, mesg, a_err_event->minor_code);
 | |
|         if (ext) {
 | |
|             snprintf(mesg, sizeof(mesg), "%s.%d",
 | |
|                      ext->name, a_err_event->minor_code);
 | |
|             XGetErrorDatabaseText(dpy, "XRequest", mesg, "", buffer, BUFSIZ);
 | |
|             (void) fprintf(a_fp, " (%s)", buffer);
 | |
|         }
 | |
|         fputs("\n", a_fp);
 | |
|     }
 | |
|     if (a_err_event->error_code >= 128) {
 | |
|         /* kludge, try to find the extension that caused it */
 | |
|         buffer[0] = '\0';
 | |
|         for (ext = dpy->ext_procs; ext; ext = ext->next) {
 | |
|             if (ext->error_string)
 | |
|                 (*ext->error_string) (dpy, a_err_event->error_code, &ext->codes,
 | |
|                                       buffer, BUFSIZ);
 | |
|             if (buffer[0]) {
 | |
|                 bext = ext;
 | |
|                 break;
 | |
|             }
 | |
|             if (ext->codes.first_error &&
 | |
|                 ext->codes.first_error < (int) a_err_event->error_code &&
 | |
|                 (!bext || ext->codes.first_error > bext->codes.first_error))
 | |
|                 bext = ext;
 | |
|         }
 | |
|         if (bext)
 | |
|             snprintf(buffer, sizeof(buffer), "%s.%d", bext->name,
 | |
|                      a_err_event->error_code - bext->codes.first_error);
 | |
|         else
 | |
|             strcpy(buffer, "Value");
 | |
|         XGetErrorDatabaseText(dpy, mtype, buffer, "", mesg, BUFSIZ);
 | |
|         if (mesg[0]) {
 | |
|             fputs("  ", a_fp);
 | |
|             (void) fprintf(a_fp, mesg, a_err_event->resourceid);
 | |
|             fputs("\n", a_fp);
 | |
|         }
 | |
|         /* let extensions try to print the values */
 | |
|         for (ext = dpy->ext_procs; ext; ext = ext->next) {
 | |
|             if (ext->error_values)
 | |
|                 (*ext->error_values) (dpy, a_err_event, a_fp);
 | |
|         }
 | |
|     }
 | |
|     else if ((a_err_event->error_code == BadWindow) ||
 | |
|              (a_err_event->error_code == BadPixmap) ||
 | |
|              (a_err_event->error_code == BadCursor) ||
 | |
|              (a_err_event->error_code == BadFont) ||
 | |
|              (a_err_event->error_code == BadDrawable) ||
 | |
|              (a_err_event->error_code == BadColor) ||
 | |
|              (a_err_event->error_code == BadGC) ||
 | |
|              (a_err_event->error_code == BadIDChoice) ||
 | |
|              (a_err_event->error_code == BadValue) ||
 | |
|              (a_err_event->error_code == BadAtom)) {
 | |
|         if (a_err_event->error_code == BadValue)
 | |
|             XGetErrorDatabaseText(dpy, mtype, "Value", "Value 0x%x",
 | |
|                                   mesg, BUFSIZ);
 | |
|         else if (a_err_event->error_code == BadAtom)
 | |
|             XGetErrorDatabaseText(dpy, mtype, "AtomID", "AtomID 0x%x",
 | |
|                                   mesg, BUFSIZ);
 | |
|         else
 | |
|             XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x",
 | |
|                                   mesg, BUFSIZ);
 | |
|         fputs("  ", a_fp);
 | |
|         (void) fprintf(a_fp, mesg, a_err_event->resourceid);
 | |
|         fputs("\n", a_fp);
 | |
|     }
 | |
|     XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d",
 | |
|                           mesg, BUFSIZ);
 | |
|     fputs("  ", a_fp);
 | |
|     (void) fprintf(a_fp, mesg, a_err_event->serial);
 | |
|     XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d",
 | |
|                           mesg, BUFSIZ);
 | |
|     fputs("\n  ", a_fp);
 | |
|     (void) fprintf(a_fp, mesg, dpy->request);
 | |
|     fputs("\n", a_fp);
 | |
| }
 | |
| 
 | |
| static int
 | |
| ephyrHostXVErrorHandler(Display * a_display, XErrorEvent * a_error_event)
 | |
| {
 | |
|     EPHYR_LOG_ERROR("got an error from the host xserver:\n");
 | |
|     ephyrHostXVLogXErrorEvent(a_display, a_error_event, stderr);
 | |
|     return Success;
 | |
| }
 | |
| 
 | |
| void
 | |
| ephyrHostXVInit(void)
 | |
| {
 | |
|     static Bool s_initialized;
 | |
| 
 | |
|     if (s_initialized)
 | |
|         return;
 | |
|     XSetErrorHandler(ephyrHostXVErrorHandler);
 | |
|     s_initialized = TRUE;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| ephyrHostXVQueryAdaptors(EphyrHostXVAdaptorArray ** a_adaptors)
 | |
| {
 | |
|     EphyrHostXVAdaptorArray *result = NULL;
 | |
|     int ret = 0;
 | |
|     Bool is_ok = FALSE;
 | |
| 
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(a_adaptors, FALSE);
 | |
| 
 | |
|     EPHYR_LOG("enter\n");
 | |
| 
 | |
|     result = calloc(1, sizeof(EphyrHostXVAdaptorArray));
 | |
|     if (!result)
 | |
|         goto out;
 | |
| 
 | |
|     ret = XvQueryAdaptors(hostx_get_display(),
 | |
|                           DefaultRootWindow(hostx_get_display()),
 | |
|                           &result->nb_adaptors, &result->adaptors);
 | |
|     if (ret != Success) {
 | |
|         EPHYR_LOG_ERROR("failed to query host adaptors: %d\n", ret);
 | |
|         goto out;
 | |
|     }
 | |
|     *a_adaptors = result;
 | |
|     is_ok = TRUE;
 | |
| 
 | |
|  out:
 | |
|     EPHYR_LOG("leave\n");
 | |
|     return is_ok;
 | |
| }
 | |
| 
 | |
| void
 | |
| ephyrHostXVAdaptorArrayDelete(EphyrHostXVAdaptorArray * a_adaptors)
 | |
| {
 | |
|     if (!a_adaptors)
 | |
|         return;
 | |
|     if (a_adaptors->adaptors) {
 | |
|         XvFreeAdaptorInfo(a_adaptors->adaptors);
 | |
|         a_adaptors->adaptors = NULL;
 | |
|         a_adaptors->nb_adaptors = 0;
 | |
|     }
 | |
|     XFree(a_adaptors);
 | |
| }
 | |
| 
 | |
| int
 | |
| ephyrHostXVAdaptorArrayGetSize(const EphyrHostXVAdaptorArray * a_this)
 | |
| {
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(a_this, -1);
 | |
|     return a_this->nb_adaptors;
 | |
| }
 | |
| 
 | |
| EphyrHostXVAdaptor *
 | |
| ephyrHostXVAdaptorArrayAt(const EphyrHostXVAdaptorArray * a_this, int a_index)
 | |
| {
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(a_this, NULL);
 | |
| 
 | |
|     if (a_index >= a_this->nb_adaptors)
 | |
|         return NULL;
 | |
|     return (EphyrHostXVAdaptor *) & a_this->adaptors[a_index];
 | |
| }
 | |
| 
 | |
| char
 | |
| ephyrHostXVAdaptorGetType(const EphyrHostXVAdaptor * a_this)
 | |
| {
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(a_this, -1);
 | |
|     return ((XvAdaptorInfo *) a_this)->type;
 | |
| }
 | |
| 
 | |
| const char *
 | |
| ephyrHostXVAdaptorGetName(const EphyrHostXVAdaptor * a_this)
 | |
| {
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(a_this, NULL);
 | |
| 
 | |
|     return ((XvAdaptorInfo *) a_this)->name;
 | |
| }
 | |
| 
 | |
| EphyrHostVideoFormat *
 | |
| ephyrHostXVAdaptorGetVideoFormats(const EphyrHostXVAdaptor * a_this,
 | |
|                                   int *a_nb_formats)
 | |
| {
 | |
|     EphyrHostVideoFormat *formats = NULL;
 | |
|     int nb_formats = 0, i = 0;
 | |
|     XVisualInfo *visual_info, visual_info_template;
 | |
|     int nb_visual_info;
 | |
| 
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(a_this, NULL);
 | |
| 
 | |
|     nb_formats = ((XvAdaptorInfo *) a_this)->num_formats;
 | |
|     formats = calloc(nb_formats, sizeof(EphyrHostVideoFormat));
 | |
|     for (i = 0; i < nb_formats; i++) {
 | |
|         memset(&visual_info_template, 0, sizeof(visual_info_template));
 | |
|         visual_info_template.visualid =
 | |
|             ((XvAdaptorInfo *) a_this)->formats[i].visual_id;
 | |
|         visual_info = XGetVisualInfo(hostx_get_display(),
 | |
|                                      VisualIDMask,
 | |
|                                      &visual_info_template, &nb_visual_info);
 | |
|         formats[i].depth = ((XvAdaptorInfo *) a_this)->formats[i].depth;
 | |
|         formats[i].visual_class = visual_info->class;
 | |
|         XFree(visual_info);
 | |
|     }
 | |
|     if (a_nb_formats)
 | |
|         *a_nb_formats = nb_formats;
 | |
|     return formats;
 | |
| }
 | |
| 
 | |
| int
 | |
| ephyrHostXVAdaptorGetNbPorts(const EphyrHostXVAdaptor * a_this)
 | |
| {
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(a_this, -1);
 | |
| 
 | |
|     return ((XvAdaptorInfo *) a_this)->num_ports;
 | |
| }
 | |
| 
 | |
| int
 | |
| ephyrHostXVAdaptorGetFirstPortID(const EphyrHostXVAdaptor * a_this)
 | |
| {
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(a_this, -1);
 | |
| 
 | |
|     return ((XvAdaptorInfo *) a_this)->base_id;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| ephyrHostXVAdaptorHasPutVideo(const EphyrHostXVAdaptor * a_this, Bool *a_result)
 | |
| {
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(a_this && a_result, FALSE);
 | |
| 
 | |
|     if ((((XvAdaptorInfo *) a_this)->type & (XvVideoMask | XvInputMask)) ==
 | |
|         (XvVideoMask | XvInputMask))
 | |
|         *a_result = TRUE;
 | |
|     else
 | |
|         *a_result = FALSE;
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| ephyrHostXVAdaptorHasGetVideo(const EphyrHostXVAdaptor * a_this, Bool *a_result)
 | |
| {
 | |
|     if ((((XvAdaptorInfo *) a_this)->type & (XvVideoMask | XvOutputMask)) ==
 | |
|         (XvVideoMask | XvOutputMask))
 | |
|         *a_result = TRUE;
 | |
|     else
 | |
|         *a_result = FALSE;
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| ephyrHostXVAdaptorHasPutStill(const EphyrHostXVAdaptor * a_this, Bool *a_result)
 | |
| {
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(a_this && a_result, FALSE);
 | |
| 
 | |
|     if ((((XvAdaptorInfo *) a_this)->type & (XvStillMask | XvInputMask)) ==
 | |
|         (XvStillMask | XvInputMask))
 | |
|         *a_result = TRUE;
 | |
|     else
 | |
|         *a_result = FALSE;
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| ephyrHostXVAdaptorHasGetStill(const EphyrHostXVAdaptor * a_this, Bool *a_result)
 | |
| {
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(a_this && a_result, FALSE);
 | |
| 
 | |
|     if ((((XvAdaptorInfo *) a_this)->type & (XvStillMask | XvOutputMask)) ==
 | |
|         (XvStillMask | XvOutputMask))
 | |
|         *a_result = TRUE;
 | |
|     else
 | |
|         *a_result = FALSE;
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| ephyrHostXVAdaptorHasPutImage(const EphyrHostXVAdaptor * a_this, Bool *a_result)
 | |
| {
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(a_this && a_result, FALSE);
 | |
| 
 | |
|     if ((((XvAdaptorInfo *) a_this)->type & (XvImageMask | XvInputMask)) ==
 | |
|         (XvImageMask | XvInputMask))
 | |
|         *a_result = TRUE;
 | |
|     else
 | |
|         *a_result = FALSE;
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| ephyrHostXVQueryEncodings(int a_port_id,
 | |
|                           EphyrHostEncoding ** a_encodings,
 | |
|                           unsigned int *a_num_encodings)
 | |
| {
 | |
|     EphyrHostEncoding *encodings = NULL;
 | |
|     XvEncodingInfo *encoding_info = NULL;
 | |
|     unsigned int num_encodings = 0, i;
 | |
|     int ret = 0;
 | |
| 
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(a_encodings && a_num_encodings, FALSE);
 | |
| 
 | |
|     ret = XvQueryEncodings(hostx_get_display(),
 | |
|                            a_port_id, &num_encodings, &encoding_info);
 | |
|     if (num_encodings && encoding_info) {
 | |
|         encodings = calloc(num_encodings, sizeof(EphyrHostEncoding));
 | |
|         for (i = 0; i < num_encodings; i++) {
 | |
|             encodings[i].id = encoding_info[i].encoding_id;
 | |
|             encodings[i].name = strdup(encoding_info[i].name);
 | |
|             encodings[i].width = encoding_info[i].width;
 | |
|             encodings[i].height = encoding_info[i].height;
 | |
|             encodings[i].rate.numerator = encoding_info[i].rate.numerator;
 | |
|             encodings[i].rate.denominator = encoding_info[i].rate.denominator;
 | |
|         }
 | |
|     }
 | |
|     if (encoding_info) {
 | |
|         XvFreeEncodingInfo(encoding_info);
 | |
|         encoding_info = NULL;
 | |
|     }
 | |
|     *a_encodings = encodings;
 | |
|     *a_num_encodings = num_encodings;
 | |
| 
 | |
|     if (ret != Success)
 | |
|         return FALSE;
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| void
 | |
| ephyrHostEncodingsDelete(EphyrHostEncoding * a_encodings, int a_num_encodings)
 | |
| {
 | |
|     int i = 0;
 | |
| 
 | |
|     if (!a_encodings)
 | |
|         return;
 | |
|     for (i = 0; i < a_num_encodings; i++) {
 | |
|         free(a_encodings[i].name);
 | |
|         a_encodings[i].name = NULL;
 | |
|     }
 | |
|     free(a_encodings);
 | |
| }
 | |
| 
 | |
| void
 | |
| ephyrHostAttributesDelete(EphyrHostAttribute * a_attributes)
 | |
| {
 | |
|     if (!a_attributes)
 | |
|         return;
 | |
|     XFree(a_attributes);
 | |
| }
 | |
| 
 | |
| Bool
 | |
| ephyrHostXVQueryPortAttributes(int a_port_id,
 | |
|                                EphyrHostAttribute ** a_attributes,
 | |
|                                int *a_num_attributes)
 | |
| {
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(a_attributes && a_num_attributes, FALSE);
 | |
| 
 | |
|     *a_attributes =
 | |
|         (EphyrHostAttribute *) XvQueryPortAttributes(hostx_get_display(),
 | |
|                                                      a_port_id,
 | |
|                                                      a_num_attributes);
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| ephyrHostXVQueryImageFormats(int a_port_id,
 | |
|                              EphyrHostImageFormat ** a_formats,
 | |
|                              int *a_num_format)
 | |
| {
 | |
|     XvImageFormatValues *result = NULL;
 | |
| 
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(a_formats && a_num_format, FALSE);
 | |
| 
 | |
|     result = XvListImageFormats(hostx_get_display(), a_port_id, a_num_format);
 | |
|     *a_formats = (EphyrHostImageFormat *) result;
 | |
|     return TRUE;
 | |
| 
 | |
| }
 | |
| 
 | |
| Bool
 | |
| ephyrHostXVSetPortAttribute(int a_port_id, int a_atom, int a_attr_value)
 | |
| {
 | |
|     int res = Success;
 | |
| 
 | |
|     EPHYR_LOG("atom,name,value: (%d,%s,%d)\n",
 | |
|               a_atom, XGetAtomName(hostx_get_display(), a_atom), a_attr_value);
 | |
| 
 | |
|     res = XvSetPortAttribute(hostx_get_display(),
 | |
|                              a_port_id, a_atom, a_attr_value);
 | |
|     if (res != Success) {
 | |
|         EPHYR_LOG_ERROR("XvSetPortAttribute() failed: %d\n", res);
 | |
|         return FALSE;
 | |
|     }
 | |
|     XFlush(hostx_get_display());
 | |
|     EPHYR_LOG("leave\n");
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| ephyrHostXVGetPortAttribute(int a_port_id, int a_atom, int *a_attr_value)
 | |
| {
 | |
|     int res = Success;
 | |
|     Bool ret = FALSE;
 | |
| 
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(a_attr_value, FALSE);
 | |
| 
 | |
|     EPHYR_LOG("enter, a_port_id: %d, a_atomid: %d, attr_name: %s\n",
 | |
|               a_port_id, a_atom, XGetAtomName(hostx_get_display(), a_atom));
 | |
| 
 | |
|     res = XvGetPortAttribute(hostx_get_display(),
 | |
|                              a_port_id, a_atom, a_attr_value);
 | |
|     if (res != Success) {
 | |
|         EPHYR_LOG_ERROR("XvGetPortAttribute() failed: %d \n", res);
 | |
|         goto out;
 | |
|     }
 | |
|     EPHYR_LOG("atom,value: (%d, %d)\n", a_atom, *a_attr_value);
 | |
| 
 | |
|     ret = TRUE;
 | |
| 
 | |
|  out:
 | |
|     EPHYR_LOG("leave\n");
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| ephyrHostXVQueryBestSize(int a_port_id,
 | |
|                          Bool a_motion,
 | |
|                          unsigned int a_frame_w,
 | |
|                          unsigned int a_frame_h,
 | |
|                          unsigned int a_drw_w,
 | |
|                          unsigned int a_drw_h,
 | |
|                          unsigned int *a_actual_w, unsigned int *a_actual_h)
 | |
| {
 | |
|     int res = 0;
 | |
|     Bool is_ok = FALSE;
 | |
| 
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(a_actual_w && a_actual_h, FALSE);
 | |
| 
 | |
|     EPHYR_LOG("enter: frame (%dx%d), drw (%dx%d)\n",
 | |
|               a_frame_w, a_frame_h, a_drw_w, a_drw_h);
 | |
| 
 | |
|     res = XvQueryBestSize(hostx_get_display(),
 | |
|                           a_port_id,
 | |
|                           a_motion,
 | |
|                           a_frame_w, a_frame_h,
 | |
|                           a_drw_w, a_drw_h, a_actual_w, a_actual_h);
 | |
|     if (res != Success) {
 | |
|         EPHYR_LOG_ERROR("XvQueryBestSize() failed: %d\n", res);
 | |
|         goto out;
 | |
|     }
 | |
|     XSync(hostx_get_display(), FALSE);
 | |
| 
 | |
|     EPHYR_LOG("actual (%dx%d)\n", *a_actual_w, *a_actual_h);
 | |
|     is_ok = TRUE;
 | |
| 
 | |
|  out:
 | |
|     EPHYR_LOG("leave\n");
 | |
|     return is_ok;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| xv_wire_to_event(Display * dpy, XEvent * host, xEvent *wire)
 | |
| {
 | |
|     XExtDisplayInfo *info = xv_find_display(dpy);
 | |
|     XvEvent *re = (XvEvent *) host;
 | |
|     xvEvent *event = (xvEvent *) wire;
 | |
| 
 | |
|     XvCheckExtension(dpy, info, False);
 | |
| 
 | |
|     switch ((event->u.u.type & 0x7F) - info->codes->first_event) {
 | |
|     case XvVideoNotify:
 | |
|         re->xvvideo.type = event->u.u.type & 0x7f;
 | |
|         re->xvvideo.serial = _XSetLastRequestRead(dpy, (xGenericReply *) event);
 | |
|         re->xvvideo.send_event = ((event->u.u.type & 0x80) != 0);
 | |
|         re->xvvideo.display = dpy;
 | |
|         re->xvvideo.time = event->u.videoNotify.time;
 | |
|         re->xvvideo.reason = event->u.videoNotify.reason;
 | |
|         re->xvvideo.drawable = event->u.videoNotify.drawable;
 | |
|         re->xvvideo.port_id = event->u.videoNotify.port;
 | |
|         break;
 | |
|     case XvPortNotify:
 | |
|         re->xvport.type = event->u.u.type & 0x7f;
 | |
|         re->xvport.serial = _XSetLastRequestRead(dpy, (xGenericReply *) event);
 | |
|         re->xvport.send_event = ((event->u.u.type & 0x80) != 0);
 | |
|         re->xvport.display = dpy;
 | |
|         re->xvport.time = event->u.portNotify.time;
 | |
|         re->xvport.port_id = event->u.portNotify.port;
 | |
|         re->xvport.attribute = event->u.portNotify.attribute;
 | |
|         re->xvport.value = event->u.portNotify.value;
 | |
|         break;
 | |
|     default:
 | |
|         return False;
 | |
|     }
 | |
| 
 | |
|     return True;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| ephyrHostXVQueryImageAttributes(int a_port_id,
 | |
|                                 int a_image_id /*image fourcc code */ ,
 | |
|                                 unsigned short *a_width,
 | |
|                                 unsigned short *a_height,
 | |
|                                 int *a_image_size,
 | |
|                                 int *a_pitches, int *a_offsets)
 | |
| {
 | |
|     Display *dpy = hostx_get_display();
 | |
|     Bool ret = FALSE;
 | |
|     XExtDisplayInfo *info = xv_find_display(dpy);
 | |
|     xvQueryImageAttributesReq *req = NULL;
 | |
|     xvQueryImageAttributesReply rep;
 | |
| 
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(a_width, FALSE);
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(a_height, FALSE);
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(a_image_size, FALSE);
 | |
| 
 | |
|     XvCheckExtension(dpy, info, FALSE);
 | |
| 
 | |
|     LockDisplay(dpy);
 | |
| 
 | |
|     XvGetReq(QueryImageAttributes, req);
 | |
|     req->id = a_image_id;
 | |
|     req->port = a_port_id;
 | |
|     req->width = *a_width;
 | |
|     req->height = *a_height;
 | |
|     /*
 | |
|      * read the reply
 | |
|      */
 | |
|     if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
 | |
|         EPHYR_LOG_ERROR("QeryImageAttribute req failed\n");
 | |
|         goto out;
 | |
|     }
 | |
|     if (a_pitches && a_offsets) {
 | |
|         _XRead(dpy, (char *) a_pitches, rep.num_planes << 2);
 | |
|         _XRead(dpy, (char *) a_offsets, rep.num_planes << 2);
 | |
|     }
 | |
|     else {
 | |
|         _XEatData(dpy, rep.length << 2);
 | |
|     }
 | |
|     *a_width = rep.width;
 | |
|     *a_height = rep.height;
 | |
|     *a_image_size = rep.data_size;
 | |
| 
 | |
|     ret = TRUE;
 | |
| 
 | |
|  out:
 | |
|     UnlockDisplay(dpy);
 | |
|     SyncHandle();
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| ephyrHostGetAtom(const char *a_name, Bool a_create_if_not_exists, int *a_atom)
 | |
| {
 | |
|     int atom = None;
 | |
| 
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(a_atom, FALSE);
 | |
| 
 | |
|     atom = XInternAtom(hostx_get_display(), a_name, a_create_if_not_exists);
 | |
|     if (atom == None) {
 | |
|         return FALSE;
 | |
|     }
 | |
|     *a_atom = atom;
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| char *
 | |
| ephyrHostGetAtomName(int a_atom)
 | |
| {
 | |
|     return XGetAtomName(hostx_get_display(), a_atom);
 | |
| }
 | |
| 
 | |
| void
 | |
| ephyrHostFree(void *a_pointer)
 | |
| {
 | |
|     if (a_pointer)
 | |
|         XFree(a_pointer);
 | |
| }
 | |
| 
 | |
| Bool
 | |
| ephyrHostXVPutImage(int a_screen_num,
 | |
|                     int a_port_id,
 | |
|                     int a_image_id,
 | |
|                     int a_drw_x,
 | |
|                     int a_drw_y,
 | |
|                     int a_drw_w,
 | |
|                     int a_drw_h,
 | |
|                     int a_src_x,
 | |
|                     int a_src_y,
 | |
|                     int a_src_w,
 | |
|                     int a_src_h,
 | |
|                     int a_image_width,
 | |
|                     int a_image_height,
 | |
|                     unsigned char *a_buf,
 | |
|                     EphyrHostBox * a_clip_rects, int a_clip_rect_nums)
 | |
| {
 | |
|     Bool is_ok = TRUE;
 | |
|     XvImage *xv_image = NULL;
 | |
|     GC gc = 0;
 | |
|     XGCValues gc_values;
 | |
|     Display *dpy = hostx_get_display();
 | |
|     XRectangle *rects = NULL;
 | |
|     int res = 0;
 | |
| 
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(a_buf, FALSE);
 | |
| 
 | |
|     EPHYR_LOG("enter, num_clip_rects: %d\n", a_clip_rect_nums);
 | |
| 
 | |
|     memset(&gc_values, 0, sizeof(gc_values));
 | |
|     gc = XCreateGC(dpy, hostx_get_window(a_screen_num), 0L, &gc_values);
 | |
|     if (!gc) {
 | |
|         EPHYR_LOG_ERROR("failed to create gc \n");
 | |
|         goto out;
 | |
|     }
 | |
|     xv_image = (XvImage *) XvCreateImage(hostx_get_display(),
 | |
|                                          a_port_id, a_image_id,
 | |
|                                          NULL, a_image_width, a_image_height);
 | |
|     if (!xv_image) {
 | |
|         EPHYR_LOG_ERROR("failed to create image\n");
 | |
|         goto out;
 | |
|     }
 | |
|     xv_image->data = (char *) a_buf;
 | |
|     if (a_clip_rect_nums) {
 | |
|         int i = 0;
 | |
| 
 | |
|         rects = calloc(a_clip_rect_nums, sizeof(XRectangle));
 | |
|         for (i = 0; i < a_clip_rect_nums; i++) {
 | |
|             rects[i].x = a_clip_rects[i].x1;
 | |
|             rects[i].y = a_clip_rects[i].y1;
 | |
|             rects[i].width = a_clip_rects[i].x2 - a_clip_rects[i].x1;
 | |
|             rects[i].height = a_clip_rects[i].y2 - a_clip_rects[i].y1;
 | |
|             EPHYR_LOG("(x,y,w,h): (%d,%d,%d,%d)\n",
 | |
|                       rects[i].x, rects[i].y, rects[i].width, rects[i].height);
 | |
|         }
 | |
|         XSetClipRectangles(dpy, gc, 0, 0, rects, a_clip_rect_nums, YXBanded);
 | |
|         /*this always returns 1 */
 | |
|     }
 | |
|     res = XvPutImage(dpy, a_port_id,
 | |
|                      hostx_get_window(a_screen_num),
 | |
|                      gc, xv_image,
 | |
|                      a_src_x, a_src_y, a_src_w, a_src_h,
 | |
|                      a_drw_x, a_drw_y, a_drw_w, a_drw_h);
 | |
|     if (res != Success) {
 | |
|         EPHYR_LOG_ERROR("XvPutImage() failed: %d\n", res);
 | |
|         goto out;
 | |
|     }
 | |
|     is_ok = TRUE;
 | |
| 
 | |
|  out:
 | |
|     if (xv_image) {
 | |
|         XFree(xv_image);
 | |
|         xv_image = NULL;
 | |
|     }
 | |
|     if (gc) {
 | |
|         XFreeGC(dpy, gc);
 | |
|         gc = NULL;
 | |
|     }
 | |
|     free(rects);
 | |
|     rects = NULL;
 | |
|     EPHYR_LOG("leave\n");
 | |
|     return is_ok;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| ephyrHostXVPutVideo(int a_screen_num, int a_port_id,
 | |
|                     int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h,
 | |
|                     int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h)
 | |
| {
 | |
|     Bool is_ok = FALSE;
 | |
|     int res = FALSE;
 | |
|     GC gc = 0;
 | |
|     XGCValues gc_values;
 | |
|     Display *dpy = hostx_get_display();
 | |
| 
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(dpy, FALSE);
 | |
| 
 | |
|     gc = XCreateGC(dpy, hostx_get_window(a_screen_num), 0L, &gc_values);
 | |
|     if (!gc) {
 | |
|         EPHYR_LOG_ERROR("failed to create gc \n");
 | |
|         goto out;
 | |
|     }
 | |
|     res = XvPutVideo(dpy, a_port_id, hostx_get_window(a_screen_num), gc,
 | |
|                      a_vid_x, a_vid_y, a_vid_w, a_vid_h,
 | |
|                      a_drw_x, a_drw_y, a_drw_w, a_drw_h);
 | |
| 
 | |
|     if (res != Success) {
 | |
|         EPHYR_LOG_ERROR("XvPutVideo() failed: %d\n", res);
 | |
|         goto out;
 | |
|     }
 | |
| 
 | |
|     is_ok = TRUE;
 | |
| 
 | |
|  out:
 | |
|     if (gc) {
 | |
|         XFreeGC(dpy, gc);
 | |
|         gc = NULL;
 | |
|     }
 | |
|     return is_ok;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| ephyrHostXVGetVideo(int a_screen_num, int a_port_id,
 | |
|                     int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h,
 | |
|                     int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h)
 | |
| {
 | |
|     Bool is_ok = FALSE;
 | |
|     int res = FALSE;
 | |
|     GC gc = 0;
 | |
|     XGCValues gc_values;
 | |
|     Display *dpy = hostx_get_display();
 | |
| 
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(dpy, FALSE);
 | |
| 
 | |
|     gc = XCreateGC(dpy, hostx_get_window(a_screen_num), 0L, &gc_values);
 | |
|     if (!gc) {
 | |
|         EPHYR_LOG_ERROR("failed to create gc \n");
 | |
|         goto out;
 | |
|     }
 | |
|     res = XvGetVideo(dpy, a_port_id, hostx_get_window(a_screen_num), gc,
 | |
|                      a_vid_x, a_vid_y, a_vid_w, a_vid_h,
 | |
|                      a_drw_x, a_drw_y, a_drw_w, a_drw_h);
 | |
| 
 | |
|     if (res != Success) {
 | |
|         EPHYR_LOG_ERROR("XvGetVideo() failed: %d\n", res);
 | |
|         goto out;
 | |
|     }
 | |
| 
 | |
|     is_ok = TRUE;
 | |
| 
 | |
|  out:
 | |
|     if (gc) {
 | |
|         XFreeGC(dpy, gc);
 | |
|         gc = NULL;
 | |
|     }
 | |
|     return is_ok;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| ephyrHostXVPutStill(int a_screen_num, int a_port_id,
 | |
|                     int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h,
 | |
|                     int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h)
 | |
| {
 | |
|     Bool is_ok = FALSE;
 | |
|     int res = FALSE;
 | |
|     GC gc = 0;
 | |
|     XGCValues gc_values;
 | |
|     Display *dpy = hostx_get_display();
 | |
| 
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(dpy, FALSE);
 | |
| 
 | |
|     gc = XCreateGC(dpy, hostx_get_window(a_screen_num), 0L, &gc_values);
 | |
|     if (!gc) {
 | |
|         EPHYR_LOG_ERROR("failed to create gc \n");
 | |
|         goto out;
 | |
|     }
 | |
|     res = XvPutStill(dpy, a_port_id, hostx_get_window(a_screen_num), gc,
 | |
|                      a_vid_x, a_vid_y, a_vid_w, a_vid_h,
 | |
|                      a_drw_x, a_drw_y, a_drw_w, a_drw_h);
 | |
| 
 | |
|     if (res != Success) {
 | |
|         EPHYR_LOG_ERROR("XvPutStill() failed: %d\n", res);
 | |
|         goto out;
 | |
|     }
 | |
| 
 | |
|     is_ok = TRUE;
 | |
| 
 | |
|  out:
 | |
|     if (gc) {
 | |
|         XFreeGC(dpy, gc);
 | |
|         gc = NULL;
 | |
|     }
 | |
|     return is_ok;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| ephyrHostXVGetStill(int a_screen_num, int a_port_id,
 | |
|                     int a_vid_x, int a_vid_y, int a_vid_w, int a_vid_h,
 | |
|                     int a_drw_x, int a_drw_y, int a_drw_w, int a_drw_h)
 | |
| {
 | |
|     Bool is_ok = FALSE;
 | |
|     int res = FALSE;
 | |
|     GC gc = 0;
 | |
|     XGCValues gc_values;
 | |
|     Display *dpy = hostx_get_display();
 | |
| 
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(dpy, FALSE);
 | |
| 
 | |
|     gc = XCreateGC(dpy, hostx_get_window(a_screen_num), 0L, &gc_values);
 | |
|     if (!gc) {
 | |
|         EPHYR_LOG_ERROR("failed to create gc \n");
 | |
|         goto out;
 | |
|     }
 | |
|     res = XvGetStill(dpy, a_port_id, hostx_get_window(a_screen_num), gc,
 | |
|                      a_vid_x, a_vid_y, a_vid_w, a_vid_h,
 | |
|                      a_drw_x, a_drw_y, a_drw_w, a_drw_h);
 | |
| 
 | |
|     if (res != Success) {
 | |
|         EPHYR_LOG_ERROR("XvGetStill() failed: %d\n", res);
 | |
|         goto out;
 | |
|     }
 | |
| 
 | |
|     is_ok = TRUE;
 | |
| 
 | |
|  out:
 | |
|     if (gc) {
 | |
|         XFreeGC(dpy, gc);
 | |
|         gc = NULL;
 | |
|     }
 | |
|     return is_ok;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| ephyrHostXVStopVideo(int a_screen_num, int a_port_id)
 | |
| {
 | |
|     int ret = 0;
 | |
|     Bool is_ok = FALSE;
 | |
|     Display *dpy = hostx_get_display();
 | |
| 
 | |
|     EPHYR_RETURN_VAL_IF_FAIL(dpy, FALSE);
 | |
| 
 | |
|     EPHYR_LOG("enter\n");
 | |
| 
 | |
|     ret = XvStopVideo(dpy, a_port_id, hostx_get_window(a_screen_num));
 | |
|     if (ret != Success) {
 | |
|         EPHYR_LOG_ERROR("XvStopVideo() failed: %d \n", ret);
 | |
|         goto out;
 | |
|     }
 | |
|     is_ok = TRUE;
 | |
| 
 | |
|  out:
 | |
|     EPHYR_LOG("leave\n");
 | |
|     return is_ok;
 | |
| }
 |