/* * Xephyr - A kdrive X server thats runs in a host X window. * Authored by Matthew Allum * * 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 */ #ifdef HAVE_CONFIG_H #include #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 #include #include #include #include #include #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 = 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; iu.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 ; }