4ba76a7e2b
We can now launch GL or XV apps in any of the Xephyr screens we want. * hw/kdrive/ephyr/hostx.c,h: (hostx_get_window): (hostx_create_window): make these functions be screen number aware. * hw/kdrive/ephyr/XF86dri.c : fix some compiler warnings. * hw/kdrive/ephyr/ephyrdri.c: (ephyrDRIQueryDirectRenderingCapable), (ephyrDRIOpenConnection), (ephyrDRIAuthConnection), (ephyrDRICloseConnection), (ephyrDRIGetClientDriverName), (ephyrDRICreateContext), (ephyrDRIDestroyContext), (ephyrDRICreateDrawable), (ephyrDRIGetDrawableInfo), (ephyrDRIGetDeviceInfo): in all those functions, don't forward the screen number we receive - from the client - to the host X. We (Xephyr) are always targetting the same X display screen, which is the one Xephyr got launched against. So we enforce that in the code. * hw/kdrive/ephyr/ephyrdriext.c: (EphyrMirrorHostVisuals): make this duplicate the visuals of the host X default screen into a given Xephyr screen. This way we have a chance to update the visuals of all Xephyr screen to make them mirror those of the host X. (many other places): specify screen number where required by the api change in hostx.h. * hw/kdrive/ephyr/ephyrglxext.c: specify screen number where required by the api change in hostx.h * hw/kdrive/ephyr/ephyrhostglx.c: don't forward the screen number we receive - from the client - to the host X. We (Xephyr) are always targetting the same X display screen, which is the one Xephyr got launched against. So we enforce that in the code. * hw/kdrive/ephyr/ephyrhostvideo.c,h: take in account the screen number received from the client app. This is useful to know on which Xephyr screen we need to display video stuff. * hw/kdrive/ephyr/ephyrvideo.c: update this to reflect the API change in hw/kdrive/ephyr/ephyrhostvideo.h. (ephyrSetPortAttribute): when parameters are not valid - they exceed their validity range - send them to the host anyway and do not return an error to clients. Some host expose buggy validity range, so rejecting client for that is too harsh.
1005 lines
30 KiB
C
1005 lines
30 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
|
|
#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) {
|
|
sprintf(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) {
|
|
sprintf(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)
|
|
sprintf(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 = Xcalloc (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 = Xcalloc (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)
|
|
*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)
|
|
*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)
|
|
*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)
|
|
*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)
|
|
*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 = Xcalloc (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++) {
|
|
if (a_encodings[i].name) {
|
|
xfree (a_encodings[i].name) ;
|
|
a_encodings[i].name = NULL ;
|
|
}
|
|
}
|
|
xfree (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 ;
|
|
}
|
|
if (rects) {
|
|
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 ;
|
|
}
|
|
|