xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

ephyrvideo.c (41730B)


      1 /*
      2  * Xephyr - A kdrive X server that runs in a host X window.
      3  *          Authored by Matthew Allum <mallum@openedhand.com>
      4  *
      5  * Copyright © 2007 OpenedHand Ltd
      6  *
      7  * Permission to use, copy, modify, distribute, and sell this software and its
      8  * documentation for any purpose is hereby granted without fee, provided that
      9  * the above copyright notice appear in all copies and that both that
     10  * copyright notice and this permission notice appear in supporting
     11  * documentation, and that the name of OpenedHand Ltd not be used in
     12  * advertising or publicity pertaining to distribution of the software without
     13  * specific, written prior permission. OpenedHand Ltd makes no
     14  * representations about the suitability of this software for any purpose.  It
     15  * is provided "as is" without express or implied warranty.
     16  *
     17  * OpenedHand Ltd DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     18  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     19  * EVENT SHALL OpenedHand Ltd BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     20  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     21  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     22  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     23  * PERFORMANCE OF THIS SOFTWARE.
     24  *
     25  * Authors:
     26  *    Dodji Seketeli <dodji@openedhand.com>
     27  */
     28 
     29 #ifdef HAVE_DIX_CONFIG_H
     30 #include <dix-config.h>
     31 #endif
     32 #include <string.h>
     33 #include <X11/extensions/Xv.h>
     34 #include <xcb/xcb.h>
     35 #include <xcb/xcb_aux.h>
     36 #include <xcb/xv.h>
     37 #include "ephyrlog.h"
     38 #include "kdrive.h"
     39 #include "kxv.h"
     40 #include "ephyr.h"
     41 #include "hostx.h"
     42 
     43 struct _EphyrXVPriv {
     44     xcb_xv_query_adaptors_reply_t *host_adaptors;
     45     KdVideoAdaptorPtr adaptors;
     46     int num_adaptors;
     47 };
     48 typedef struct _EphyrXVPriv EphyrXVPriv;
     49 
     50 struct _EphyrPortPriv {
     51     int port_number;
     52     KdVideoAdaptorPtr current_adaptor;
     53     EphyrXVPriv *xv_priv;
     54     unsigned char *image_buf;
     55     int image_buf_size;
     56     int image_id;
     57     int drw_x, drw_y, drw_w, drw_h;
     58     int src_x, src_y, src_w, src_h;
     59     int image_width, image_height;
     60 };
     61 typedef struct _EphyrPortPriv EphyrPortPriv;
     62 
     63 static Bool ephyrLocalAtomToHost(int a_local_atom, int *a_host_atom);
     64 
     65 static EphyrXVPriv *ephyrXVPrivNew(void);
     66 static void ephyrXVPrivDelete(EphyrXVPriv * a_this);
     67 static Bool ephyrXVPrivQueryHostAdaptors(EphyrXVPriv * a_this);
     68 static Bool ephyrXVPrivSetAdaptorsHooks(EphyrXVPriv * a_this);
     69 static Bool ephyrXVPrivRegisterAdaptors(EphyrXVPriv * a_this,
     70                                         ScreenPtr a_screen);
     71 
     72 static Bool ephyrXVPrivIsAttrValueValid(XvAttributePtr a_attrs,
     73                                         int a_attrs_len,
     74                                         const char *a_attr_name,
     75                                         int a_attr_value, Bool *a_is_valid);
     76 
     77 static Bool ephyrXVPrivGetImageBufSize(int a_port_id,
     78                                        int a_image_id,
     79                                        unsigned short a_width,
     80                                        unsigned short a_height, int *a_size);
     81 
     82 static Bool ephyrXVPrivSaveImageToPortPriv(EphyrPortPriv * a_port_priv,
     83                                            const unsigned char *a_image,
     84                                            int a_image_len);
     85 
     86 static void ephyrStopVideo(KdScreenInfo * a_info,
     87                            void *a_xv_priv, Bool a_exit);
     88 
     89 static int ephyrSetPortAttribute(KdScreenInfo * a_info,
     90                                  Atom a_attr_name,
     91                                  int a_attr_value, void *a_port_priv);
     92 
     93 static int ephyrGetPortAttribute(KdScreenInfo * a_screen_info,
     94                                  Atom a_attr_name,
     95                                  int *a_attr_value, void *a_port_priv);
     96 
     97 static void ephyrQueryBestSize(KdScreenInfo * a_info,
     98                                Bool a_motion,
     99                                short a_src_w,
    100                                short a_src_h,
    101                                short a_drw_w,
    102                                short a_drw_h,
    103                                unsigned int *a_prefered_w,
    104                                unsigned int *a_prefered_h, void *a_port_priv);
    105 
    106 static int ephyrPutImage(KdScreenInfo * a_info,
    107                          DrawablePtr a_drawable,
    108                          short a_src_x,
    109                          short a_src_y,
    110                          short a_drw_x,
    111                          short a_drw_y,
    112                          short a_src_w,
    113                          short a_src_h,
    114                          short a_drw_w,
    115                          short a_drw_h,
    116                          int a_id,
    117                          unsigned char *a_buf,
    118                          short a_width,
    119                          short a_height,
    120                          Bool a_sync,
    121                          RegionPtr a_clipping_region, void *a_port_priv);
    122 
    123 static int ephyrReputImage(KdScreenInfo * a_info,
    124                            DrawablePtr a_drawable,
    125                            short a_drw_x,
    126                            short a_drw_y,
    127                            RegionPtr a_clipping_region, void *a_port_priv);
    128 
    129 static int ephyrPutVideo(KdScreenInfo * a_info,
    130                          DrawablePtr a_drawable,
    131                          short a_vid_x, short a_vid_y,
    132                          short a_drw_x, short a_drw_y,
    133                          short a_vid_w, short a_vid_h,
    134                          short a_drw_w, short a_drw_h,
    135                          RegionPtr a_clip_region, void *a_port_priv);
    136 
    137 static int ephyrGetVideo(KdScreenInfo * a_info,
    138                          DrawablePtr a_drawable,
    139                          short a_vid_x, short a_vid_y,
    140                          short a_drw_x, short a_drw_y,
    141                          short a_vid_w, short a_vid_h,
    142                          short a_drw_w, short a_drw_h,
    143                          RegionPtr a_clip_region, void *a_port_priv);
    144 
    145 static int ephyrPutStill(KdScreenInfo * a_info,
    146                          DrawablePtr a_drawable,
    147                          short a_vid_x, short a_vid_y,
    148                          short a_drw_x, short a_drw_y,
    149                          short a_vid_w, short a_vid_h,
    150                          short a_drw_w, short a_drw_h,
    151                          RegionPtr a_clip_region, void *a_port_priv);
    152 
    153 static int ephyrGetStill(KdScreenInfo * a_info,
    154                          DrawablePtr a_drawable,
    155                          short a_vid_x, short a_vid_y,
    156                          short a_drw_x, short a_drw_y,
    157                          short a_vid_w, short a_vid_h,
    158                          short a_drw_w, short a_drw_h,
    159                          RegionPtr a_clip_region, void *a_port_priv);
    160 
    161 static int ephyrQueryImageAttributes(KdScreenInfo * a_info,
    162                                      int a_id,
    163                                      unsigned short *a_w,
    164                                      unsigned short *a_h,
    165                                      int *a_pitches, int *a_offsets);
    166 static int s_base_port_id;
    167 
    168 /**************
    169  * <helpers>
    170  * ************/
    171 
    172 static Bool
    173 adaptor_has_flags(const xcb_xv_adaptor_info_t *adaptor, uint32_t flags)
    174 {
    175     return (adaptor->type & flags) == flags;
    176 }
    177 
    178 static Bool
    179 ephyrLocalAtomToHost(int a_local_atom, int *a_host_atom)
    180 {
    181     xcb_connection_t *conn = hostx_get_xcbconn();
    182     xcb_intern_atom_cookie_t cookie;
    183     xcb_intern_atom_reply_t *reply;
    184     const char *atom_name = NULL;
    185 
    186     EPHYR_RETURN_VAL_IF_FAIL(a_host_atom, FALSE);
    187 
    188     if (!ValidAtom(a_local_atom))
    189         return FALSE;
    190 
    191     atom_name = NameForAtom(a_local_atom);
    192 
    193     if (!atom_name)
    194         return FALSE;
    195 
    196     cookie = xcb_intern_atom(conn, FALSE, strlen(atom_name), atom_name);
    197     reply = xcb_intern_atom_reply(conn, cookie, NULL);
    198     if (!reply || reply->atom == None) {
    199         EPHYR_LOG_ERROR("no atom for string %s defined in host X\n", atom_name);
    200         return FALSE;
    201     }
    202 
    203     *a_host_atom = reply->atom;
    204     free(reply);
    205 
    206     return TRUE;
    207 }
    208 
    209 /**************
    210  *</helpers>
    211  * ************/
    212 
    213 Bool
    214 ephyrInitVideo(ScreenPtr pScreen)
    215 {
    216     Bool is_ok = FALSE;
    217 
    218     KdScreenPriv(pScreen);
    219     KdScreenInfo *screen = pScreenPriv->screen;
    220     static EphyrXVPriv *xv_priv;
    221 
    222     EPHYR_LOG("enter\n");
    223 
    224     if (screen->fb.bitsPerPixel == 8) {
    225         EPHYR_LOG_ERROR("8 bits depth not supported\n");
    226         return FALSE;
    227     }
    228 
    229     if (!hostx_has_extension(&xcb_xv_id)) {
    230         EPHYR_LOG_ERROR("Host has no XVideo extension\n");
    231         return FALSE;
    232     }
    233 
    234     if (!xv_priv) {
    235         xv_priv = ephyrXVPrivNew();
    236     }
    237     if (!xv_priv) {
    238         EPHYR_LOG_ERROR("failed to create xv_priv\n");
    239         goto out;
    240     }
    241 
    242     if (!ephyrXVPrivRegisterAdaptors(xv_priv, pScreen)) {
    243         EPHYR_LOG_ERROR("failed to register adaptors\n");
    244         goto out;
    245     }
    246     is_ok = TRUE;
    247 
    248  out:
    249     return is_ok;
    250 }
    251 
    252 static EphyrXVPriv *
    253 ephyrXVPrivNew(void)
    254 {
    255     EphyrXVPriv *xv_priv = NULL;
    256 
    257     EPHYR_LOG("enter\n");
    258 
    259     xv_priv = calloc(1, sizeof(EphyrXVPriv));
    260     if (!xv_priv) {
    261         EPHYR_LOG_ERROR("failed to create EphyrXVPriv\n");
    262         goto error;
    263     }
    264 
    265     if (!ephyrXVPrivQueryHostAdaptors(xv_priv)) {
    266         EPHYR_LOG_ERROR("failed to query the host x for xv properties\n");
    267         goto error;
    268     }
    269     if (!ephyrXVPrivSetAdaptorsHooks(xv_priv)) {
    270         EPHYR_LOG_ERROR("failed to set xv_priv hooks\n");
    271         goto error;
    272     }
    273 
    274     EPHYR_LOG("leave\n");
    275     return xv_priv;
    276 
    277  error:
    278     if (xv_priv) {
    279         ephyrXVPrivDelete(xv_priv);
    280         xv_priv = NULL;
    281     }
    282     return NULL;
    283 }
    284 
    285 static void
    286 ephyrXVPrivDelete(EphyrXVPriv * a_this)
    287 {
    288     EPHYR_LOG("enter\n");
    289 
    290     if (!a_this)
    291         return;
    292     if (a_this->host_adaptors) {
    293         free(a_this->host_adaptors);
    294         a_this->host_adaptors = NULL;
    295     }
    296     free(a_this->adaptors);
    297     a_this->adaptors = NULL;
    298     free(a_this);
    299     EPHYR_LOG("leave\n");
    300 }
    301 
    302 static Bool
    303 translate_video_encodings(KdVideoAdaptorPtr adaptor,
    304                           xcb_xv_adaptor_info_t *host_adaptor)
    305 {
    306     xcb_connection_t *conn = hostx_get_xcbconn();
    307     int i;
    308     xcb_xv_query_encodings_cookie_t cookie;
    309     xcb_xv_query_encodings_reply_t *reply;
    310     xcb_xv_encoding_info_iterator_t encoding_it;
    311 
    312     cookie = xcb_xv_query_encodings(conn, host_adaptor->base_id);
    313     reply = xcb_xv_query_encodings_reply(conn, cookie, NULL);
    314     if (!reply)
    315         return FALSE;
    316 
    317     adaptor->nEncodings = reply->num_encodings;
    318     adaptor->pEncodings = calloc(adaptor->nEncodings,
    319                                   sizeof(*adaptor->pEncodings));
    320     if (!adaptor->pEncodings) {
    321         free(reply);
    322         return FALSE;
    323     }
    324 
    325     encoding_it = xcb_xv_query_encodings_info_iterator(reply);
    326     for (i = 0; i < adaptor->nEncodings; i++) {
    327         xcb_xv_encoding_info_t *encoding_info = encoding_it.data;
    328         KdVideoEncodingPtr encoding = &adaptor->pEncodings[i];
    329 
    330         encoding->id = encoding_info->encoding;
    331         encoding->name = strndup(xcb_xv_encoding_info_name(encoding_info),
    332                                  encoding_info->name_size);
    333         encoding->width = encoding_info->width;
    334         encoding->height = encoding_info->height;
    335         encoding->rate.numerator = encoding_info->rate.numerator;
    336         encoding->rate.denominator = encoding_info->rate.denominator;
    337 
    338         xcb_xv_encoding_info_next(&encoding_it);
    339     }
    340 
    341     free(reply);
    342     return TRUE;
    343 }
    344 
    345 static Bool
    346 translate_xv_attributes(KdVideoAdaptorPtr adaptor,
    347                         xcb_xv_adaptor_info_t *host_adaptor)
    348 {
    349     xcb_connection_t *conn = hostx_get_xcbconn();
    350     int i = 0;
    351     xcb_xv_attribute_info_iterator_t it;
    352     xcb_xv_query_port_attributes_cookie_t cookie =
    353         xcb_xv_query_port_attributes(conn, host_adaptor->base_id);
    354     xcb_xv_query_port_attributes_reply_t *reply =
    355         xcb_xv_query_port_attributes_reply(conn, cookie, NULL);
    356 
    357     if (!reply)
    358         return FALSE;
    359 
    360     adaptor->nAttributes = reply->num_attributes;
    361     adaptor->pAttributes = calloc(reply->num_attributes,
    362                                   sizeof(*adaptor->pAttributes));
    363     if (!adaptor->pAttributes) {
    364         EPHYR_LOG_ERROR("failed to allocate attributes\n");
    365         free(reply);
    366         return FALSE;
    367     }
    368 
    369     it = xcb_xv_query_port_attributes_attributes_iterator(reply);
    370     for (i = 0; i < reply->num_attributes; i++) {
    371         XvAttributePtr attribute = &adaptor->pAttributes[i];
    372 
    373         attribute->flags = it.data->flags;
    374         attribute->min_value = it.data->min;
    375         attribute->max_value = it.data->max;
    376         attribute->name = strndup(xcb_xv_attribute_info_name(it.data),
    377                                   it.data->size);
    378 
    379         /* make sure atoms of attrs names are created in xephyr */
    380         MakeAtom(xcb_xv_attribute_info_name(it.data), it.data->size, TRUE);
    381 
    382         xcb_xv_attribute_info_next(&it);
    383     }
    384 
    385     free(reply);
    386     return TRUE;
    387 }
    388 
    389 static Bool
    390 translate_xv_image_formats(KdVideoAdaptorPtr adaptor,
    391                            xcb_xv_adaptor_info_t *host_adaptor)
    392 {
    393     xcb_connection_t *conn = hostx_get_xcbconn();
    394     int i = 0;
    395     xcb_xv_list_image_formats_cookie_t cookie =
    396         xcb_xv_list_image_formats(conn, host_adaptor->base_id);
    397     xcb_xv_list_image_formats_reply_t *reply =
    398         xcb_xv_list_image_formats_reply(conn, cookie, NULL);
    399     xcb_xv_image_format_info_t *formats;
    400 
    401     if (!reply)
    402         return FALSE;
    403 
    404     adaptor->nImages = reply->num_formats;
    405     adaptor->pImages = calloc(reply->num_formats, sizeof(XvImageRec));
    406     if (!adaptor->pImages) {
    407         free(reply);
    408         return FALSE;
    409     }
    410 
    411     formats = xcb_xv_list_image_formats_format(reply);
    412     for (i = 0; i < reply->num_formats; i++) {
    413         XvImagePtr image = &adaptor->pImages[i];
    414 
    415         image->id = formats[i].id;
    416         image->type = formats[i].type;
    417         image->byte_order = formats[i].byte_order;
    418         memcpy(image->guid, formats[i].guid, 16);
    419         image->bits_per_pixel = formats[i].bpp;
    420         image->format = formats[i].format;
    421         image->num_planes = formats[i].num_planes;
    422         image->depth = formats[i].depth;
    423         image->red_mask = formats[i].red_mask;
    424         image->green_mask = formats[i].green_mask;
    425         image->blue_mask = formats[i].blue_mask;
    426         image->y_sample_bits = formats[i].y_sample_bits;
    427         image->u_sample_bits = formats[i].u_sample_bits;
    428         image->v_sample_bits = formats[i].v_sample_bits;
    429         image->horz_y_period = formats[i].vhorz_y_period;
    430         image->horz_u_period = formats[i].vhorz_u_period;
    431         image->horz_v_period = formats[i].vhorz_v_period;
    432         image->vert_y_period = formats[i].vvert_y_period;
    433         image->vert_u_period = formats[i].vvert_u_period;
    434         image->vert_v_period = formats[i].vvert_v_period;
    435         memcpy(image->component_order, formats[i].vcomp_order, 32);
    436         image->scanline_order = formats[i].vscanline_order;
    437     }
    438 
    439     free(reply);
    440     return TRUE;
    441 }
    442 
    443 static Bool
    444 ephyrXVPrivQueryHostAdaptors(EphyrXVPriv * a_this)
    445 {
    446     xcb_connection_t *conn = hostx_get_xcbconn();
    447     xcb_screen_t *xscreen = xcb_aux_get_screen(conn, hostx_get_screen());
    448     int base_port_id = 0, i = 0, port_priv_offset = 0;
    449     Bool is_ok = FALSE;
    450     xcb_generic_error_t *e = NULL;
    451     xcb_xv_adaptor_info_iterator_t it;
    452 
    453     EPHYR_RETURN_VAL_IF_FAIL(a_this, FALSE);
    454 
    455     EPHYR_LOG("enter\n");
    456 
    457     {
    458         xcb_xv_query_adaptors_cookie_t cookie =
    459             xcb_xv_query_adaptors(conn, xscreen->root);
    460         a_this->host_adaptors = xcb_xv_query_adaptors_reply(conn, cookie, &e);
    461         if (e) {
    462             free(e);
    463             EPHYR_LOG_ERROR("failed to query host adaptors\n");
    464             goto out;
    465         }
    466     }
    467 
    468     if (a_this->host_adaptors)
    469         a_this->num_adaptors = a_this->host_adaptors->num_adaptors;
    470     if (a_this->num_adaptors <= 0) {
    471         EPHYR_LOG_ERROR("failed to get number of host adaptors\n");
    472         goto out;
    473     }
    474     EPHYR_LOG("host has %d adaptors\n", a_this->num_adaptors);
    475     /*
    476      * copy what we can from adaptors into a_this->adaptors
    477      */
    478     if (a_this->num_adaptors) {
    479         a_this->adaptors = calloc(a_this->num_adaptors,
    480                                   sizeof(KdVideoAdaptorRec));
    481         if (!a_this->adaptors) {
    482             EPHYR_LOG_ERROR("failed to create internal adaptors\n");
    483             goto out;
    484         }
    485     }
    486 
    487     it = xcb_xv_query_adaptors_info_iterator(a_this->host_adaptors);
    488     for (i = 0; i < a_this->num_adaptors; i++) {
    489         xcb_xv_adaptor_info_t *cur_host_adaptor = it.data;
    490         xcb_xv_format_t *format = xcb_xv_adaptor_info_formats(cur_host_adaptor);
    491         int j = 0;
    492 
    493         a_this->adaptors[i].nPorts = cur_host_adaptor->num_ports;
    494         if (a_this->adaptors[i].nPorts <= 0) {
    495             EPHYR_LOG_ERROR("Could not find any port of adaptor %d\n", i);
    496             continue;
    497         }
    498         a_this->adaptors[i].type = cur_host_adaptor->type;
    499         a_this->adaptors[i].type |= XvWindowMask;
    500         a_this->adaptors[i].flags =
    501             VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT;
    502         a_this->adaptors[i].name =
    503             strndup(xcb_xv_adaptor_info_name(cur_host_adaptor),
    504                     cur_host_adaptor->name_size);
    505         if (!a_this->adaptors[i].name)
    506             a_this->adaptors[i].name = strdup("Xephyr Video Overlay");
    507         base_port_id = cur_host_adaptor->base_id;
    508         if (base_port_id < 0) {
    509             EPHYR_LOG_ERROR("failed to get port id for adaptor %d\n", i);
    510             continue;
    511         }
    512         if (!s_base_port_id)
    513             s_base_port_id = base_port_id;
    514 
    515         if (!translate_video_encodings(&a_this->adaptors[i],
    516                                        cur_host_adaptor)) {
    517             EPHYR_LOG_ERROR("failed to get encodings for port port id %d,"
    518                             " adaptors %d\n", base_port_id, i);
    519             continue;
    520         }
    521 
    522         a_this->adaptors[i].nFormats = cur_host_adaptor->num_formats;
    523         a_this->adaptors[i].pFormats =
    524             calloc(cur_host_adaptor->num_formats,
    525                    sizeof(*a_this->adaptors[i].pFormats));
    526         for (j = 0; j < cur_host_adaptor->num_formats; j++) {
    527             xcb_visualtype_t *visual =
    528                 xcb_aux_find_visual_by_id(xscreen, format[j].visual);
    529             a_this->adaptors[i].pFormats[j].depth = format[j].depth;
    530             a_this->adaptors[i].pFormats[j].class = visual->_class;
    531         }
    532 
    533         a_this->adaptors[i].pPortPrivates =
    534             calloc(a_this->adaptors[i].nPorts,
    535                    sizeof(DevUnion) + sizeof(EphyrPortPriv));
    536         port_priv_offset = a_this->adaptors[i].nPorts;
    537         for (j = 0; j < a_this->adaptors[i].nPorts; j++) {
    538             EphyrPortPriv *port_privs_base =
    539                 (EphyrPortPriv *) &a_this->adaptors[i].
    540                 pPortPrivates[port_priv_offset];
    541             EphyrPortPriv *port_priv = &port_privs_base[j];
    542 
    543             port_priv->port_number = base_port_id + j;
    544             port_priv->current_adaptor = &a_this->adaptors[i];
    545             port_priv->xv_priv = a_this;
    546             a_this->adaptors[i].pPortPrivates[j].ptr = port_priv;
    547         }
    548 
    549         if (!translate_xv_attributes(&a_this->adaptors[i], cur_host_adaptor)) {
    550         {
    551             EPHYR_LOG_ERROR("failed to get port attribute "
    552                             "for adaptor %d\n", i);
    553             continue;
    554         }
    555         }
    556 
    557         if (!translate_xv_image_formats(&a_this->adaptors[i], cur_host_adaptor)) {
    558             EPHYR_LOG_ERROR("failed to get image formats "
    559                             "for adaptor %d\n", i);
    560             continue;
    561         }
    562 
    563         xcb_xv_adaptor_info_next(&it);
    564     }
    565     is_ok = TRUE;
    566 
    567  out:
    568     EPHYR_LOG("leave\n");
    569     return is_ok;
    570 }
    571 
    572 static Bool
    573 ephyrXVPrivSetAdaptorsHooks(EphyrXVPriv * a_this)
    574 {
    575     int i = 0;
    576     xcb_xv_adaptor_info_iterator_t it;
    577 
    578     EPHYR_RETURN_VAL_IF_FAIL(a_this, FALSE);
    579 
    580     EPHYR_LOG("enter\n");
    581 
    582     it = xcb_xv_query_adaptors_info_iterator(a_this->host_adaptors);
    583     for (i = 0; i < a_this->num_adaptors; i++) {
    584         xcb_xv_adaptor_info_t *cur_host_adaptor = it.data;
    585 
    586         a_this->adaptors[i].ReputImage = ephyrReputImage;
    587         a_this->adaptors[i].StopVideo = ephyrStopVideo;
    588         a_this->adaptors[i].SetPortAttribute = ephyrSetPortAttribute;
    589         a_this->adaptors[i].GetPortAttribute = ephyrGetPortAttribute;
    590         a_this->adaptors[i].QueryBestSize = ephyrQueryBestSize;
    591         a_this->adaptors[i].QueryImageAttributes = ephyrQueryImageAttributes;
    592 
    593         if (adaptor_has_flags(cur_host_adaptor,
    594                               XCB_XV_TYPE_IMAGE_MASK | XCB_XV_TYPE_INPUT_MASK))
    595             a_this->adaptors[i].PutImage = ephyrPutImage;
    596 
    597         if (adaptor_has_flags(cur_host_adaptor,
    598                               XCB_XV_TYPE_VIDEO_MASK | XCB_XV_TYPE_INPUT_MASK))
    599             a_this->adaptors[i].PutVideo = ephyrPutVideo;
    600 
    601         if (adaptor_has_flags(cur_host_adaptor,
    602                               XCB_XV_TYPE_VIDEO_MASK | XCB_XV_TYPE_OUTPUT_MASK))
    603             a_this->adaptors[i].GetVideo = ephyrGetVideo;
    604 
    605         if (adaptor_has_flags(cur_host_adaptor,
    606                               XCB_XV_TYPE_STILL_MASK | XCB_XV_TYPE_INPUT_MASK))
    607             a_this->adaptors[i].PutStill = ephyrPutStill;
    608 
    609         if (adaptor_has_flags(cur_host_adaptor,
    610                               XCB_XV_TYPE_STILL_MASK | XCB_XV_TYPE_OUTPUT_MASK))
    611             a_this->adaptors[i].GetStill = ephyrGetStill;
    612     }
    613     EPHYR_LOG("leave\n");
    614     return TRUE;
    615 }
    616 
    617 static Bool
    618 ephyrXVPrivRegisterAdaptors(EphyrXVPriv * a_this, ScreenPtr a_screen)
    619 {
    620     Bool is_ok = FALSE;
    621 
    622     EPHYR_RETURN_VAL_IF_FAIL(a_this && a_screen, FALSE);
    623 
    624     EPHYR_LOG("enter\n");
    625 
    626     if (!a_this->num_adaptors)
    627         goto out;
    628 
    629     if (!KdXVScreenInit(a_screen, a_this->adaptors, a_this->num_adaptors)) {
    630         EPHYR_LOG_ERROR("failed to register adaptors\n");
    631         goto out;
    632     }
    633     EPHYR_LOG("there are  %d registered adaptors\n", a_this->num_adaptors);
    634     is_ok = TRUE;
    635 
    636  out:
    637 
    638     EPHYR_LOG("leave\n");
    639     return is_ok;
    640 }
    641 
    642 static Bool
    643 ephyrXVPrivIsAttrValueValid(XvAttributePtr a_attrs,
    644                             int a_attrs_len,
    645                             const char *a_attr_name,
    646                             int a_attr_value, Bool *a_is_valid)
    647 {
    648     int i = 0;
    649 
    650     EPHYR_RETURN_VAL_IF_FAIL(a_attrs && a_attr_name && a_is_valid, FALSE);
    651 
    652     for (i = 0; i < a_attrs_len; i++) {
    653         if (a_attrs[i].name && strcmp(a_attrs[i].name, a_attr_name))
    654             continue;
    655         if (a_attrs[i].min_value > a_attr_value ||
    656             a_attrs[i].max_value < a_attr_value) {
    657             *a_is_valid = FALSE;
    658             EPHYR_LOG_ERROR("attribute was not valid\n"
    659                             "value:%d. min:%d. max:%d\n",
    660                             a_attr_value,
    661                             a_attrs[i].min_value, a_attrs[i].max_value);
    662         }
    663         else {
    664             *a_is_valid = TRUE;
    665         }
    666         return TRUE;
    667     }
    668     return FALSE;
    669 }
    670 
    671 static Bool
    672 ephyrXVPrivGetImageBufSize(int a_port_id,
    673                            int a_image_id,
    674                            unsigned short a_width,
    675                            unsigned short a_height, int *a_size)
    676 {
    677     xcb_connection_t *conn = hostx_get_xcbconn();
    678     xcb_xv_query_image_attributes_cookie_t cookie;
    679     xcb_xv_query_image_attributes_reply_t *reply;
    680     Bool is_ok = FALSE;
    681 
    682     EPHYR_RETURN_VAL_IF_FAIL(a_size, FALSE);
    683 
    684     EPHYR_LOG("enter\n");
    685 
    686     cookie = xcb_xv_query_image_attributes(conn,
    687                                            a_port_id, a_image_id,
    688                                            a_width, a_height);
    689     reply = xcb_xv_query_image_attributes_reply(conn, cookie, NULL);
    690     if (!reply)
    691         goto out;
    692 
    693     *a_size = reply->data_size;
    694     is_ok = TRUE;
    695 
    696     free(reply);
    697 
    698  out:
    699     EPHYR_LOG("leave\n");
    700     return is_ok;
    701 }
    702 
    703 static Bool
    704 ephyrXVPrivSaveImageToPortPriv(EphyrPortPriv * a_port_priv,
    705                                const unsigned char *a_image_buf,
    706                                int a_image_len)
    707 {
    708     Bool is_ok = FALSE;
    709 
    710     EPHYR_LOG("enter\n");
    711 
    712     if (a_port_priv->image_buf_size < a_image_len) {
    713         unsigned char *buf = NULL;
    714 
    715         buf = realloc(a_port_priv->image_buf, a_image_len);
    716         if (!buf) {
    717             EPHYR_LOG_ERROR("failed to realloc image buffer\n");
    718             goto out;
    719         }
    720         a_port_priv->image_buf = buf;
    721         a_port_priv->image_buf_size = a_image_len;
    722     }
    723     memmove(a_port_priv->image_buf, a_image_buf, a_image_len);
    724     is_ok = TRUE;
    725 
    726  out:
    727     return is_ok;
    728     EPHYR_LOG("leave\n");
    729 }
    730 
    731 static void
    732 ephyrStopVideo(KdScreenInfo * a_info, void *a_port_priv, Bool a_exit)
    733 {
    734     xcb_connection_t *conn = hostx_get_xcbconn();
    735     EphyrPortPriv *port_priv = a_port_priv;
    736     EphyrScrPriv *scrpriv = a_info->driver;
    737 
    738     EPHYR_RETURN_IF_FAIL(port_priv);
    739 
    740     EPHYR_LOG("enter\n");
    741     xcb_xv_stop_video(conn, port_priv->port_number, scrpriv->win);
    742     EPHYR_LOG("leave\n");
    743 }
    744 
    745 static int
    746 ephyrSetPortAttribute(KdScreenInfo * a_info,
    747                       Atom a_attr_name, int a_attr_value, void *a_port_priv)
    748 {
    749     xcb_connection_t *conn = hostx_get_xcbconn();
    750     int res = Success, host_atom = 0;
    751     EphyrPortPriv *port_priv = a_port_priv;
    752     Bool is_attr_valid = FALSE;
    753 
    754     EPHYR_RETURN_VAL_IF_FAIL(port_priv, BadMatch);
    755     EPHYR_RETURN_VAL_IF_FAIL(port_priv->current_adaptor, BadMatch);
    756     EPHYR_RETURN_VAL_IF_FAIL(port_priv->current_adaptor->pAttributes, BadMatch);
    757     EPHYR_RETURN_VAL_IF_FAIL(port_priv->current_adaptor->nAttributes, BadMatch);
    758     EPHYR_RETURN_VAL_IF_FAIL(ValidAtom(a_attr_name), BadMatch);
    759 
    760     EPHYR_LOG("enter, portnum:%d, atomid:%d, attr_name:%s, attr_val:%d\n",
    761               port_priv->port_number,
    762               (int) a_attr_name, NameForAtom(a_attr_name), a_attr_value);
    763 
    764     if (!ephyrLocalAtomToHost(a_attr_name, &host_atom)) {
    765         EPHYR_LOG_ERROR("failed to convert local atom to host atom\n");
    766         res = BadMatch;
    767         goto out;
    768     }
    769 
    770     if (!ephyrXVPrivIsAttrValueValid(port_priv->current_adaptor->pAttributes,
    771                                      port_priv->current_adaptor->nAttributes,
    772                                      NameForAtom(a_attr_name),
    773                                      a_attr_value, &is_attr_valid)) {
    774         EPHYR_LOG_ERROR("failed to validate attribute %s\n",
    775                         NameForAtom(a_attr_name));
    776         /*
    777            res = BadMatch ;
    778            goto out ;
    779          */
    780     }
    781     if (!is_attr_valid) {
    782         EPHYR_LOG_ERROR("attribute %s is not valid\n",
    783                         NameForAtom(a_attr_name));
    784         /*
    785            res = BadMatch ;
    786            goto out ;
    787          */
    788     }
    789 
    790     xcb_xv_set_port_attribute(conn, port_priv->port_number,
    791                               host_atom, a_attr_value);
    792     xcb_flush(conn);
    793 
    794     res = Success;
    795  out:
    796     EPHYR_LOG("leave\n");
    797     return res;
    798 }
    799 
    800 static int
    801 ephyrGetPortAttribute(KdScreenInfo * a_screen_info,
    802                       Atom a_attr_name, int *a_attr_value, void *a_port_priv)
    803 {
    804     xcb_connection_t *conn = hostx_get_xcbconn();
    805     int res = Success, host_atom = 0;
    806     EphyrPortPriv *port_priv = a_port_priv;
    807     xcb_generic_error_t *e;
    808     xcb_xv_get_port_attribute_cookie_t cookie;
    809     xcb_xv_get_port_attribute_reply_t *reply;
    810 
    811     EPHYR_RETURN_VAL_IF_FAIL(port_priv, BadMatch);
    812     EPHYR_RETURN_VAL_IF_FAIL(ValidAtom(a_attr_name), BadMatch);
    813 
    814     EPHYR_LOG("enter, portnum:%d, atomid:%d, attr_name:%s\n",
    815               port_priv->port_number,
    816               (int) a_attr_name, NameForAtom(a_attr_name));
    817 
    818     if (!ephyrLocalAtomToHost(a_attr_name, &host_atom)) {
    819         EPHYR_LOG_ERROR("failed to convert local atom to host atom\n");
    820         res = BadMatch;
    821         goto out;
    822     }
    823 
    824     cookie = xcb_xv_get_port_attribute(conn, port_priv->port_number, host_atom);
    825     reply = xcb_xv_get_port_attribute_reply(conn, cookie, &e);
    826     if (e) {
    827         EPHYR_LOG_ERROR ("XvGetPortAttribute() failed: %d \n", e->error_code);
    828         free(e);
    829         res = BadMatch;
    830         goto out;
    831     }
    832     *a_attr_value = reply->value;
    833 
    834     free(reply);
    835 
    836     res = Success;
    837  out:
    838     EPHYR_LOG("leave\n");
    839     return res;
    840 }
    841 
    842 static void
    843 ephyrQueryBestSize(KdScreenInfo * a_info,
    844                    Bool a_motion,
    845                    short a_src_w,
    846                    short a_src_h,
    847                    short a_drw_w,
    848                    short a_drw_h,
    849                    unsigned int *a_prefered_w,
    850                    unsigned int *a_prefered_h, void *a_port_priv)
    851 {
    852     xcb_connection_t *conn = hostx_get_xcbconn();
    853     EphyrPortPriv *port_priv = a_port_priv;
    854     xcb_xv_query_best_size_cookie_t cookie =
    855         xcb_xv_query_best_size(conn,
    856                                port_priv->port_number,
    857                                a_src_w, a_src_h,
    858                                a_drw_w, a_drw_h,
    859                                a_motion);
    860     xcb_xv_query_best_size_reply_t *reply =
    861         xcb_xv_query_best_size_reply(conn, cookie, NULL);
    862 
    863     EPHYR_LOG("enter: frame (%dx%d), drw (%dx%d)\n",
    864               a_src_w, a_src_h, a_drw_w, a_drw_h);
    865 
    866     if (!reply) {
    867         EPHYR_LOG_ERROR ("XvQueryBestSize() failed\n");
    868         return;
    869     }
    870     *a_prefered_w = reply->actual_width;
    871     *a_prefered_h = reply->actual_height;
    872     EPHYR_LOG("actual (%dx%d)\n", *a_prefered_w, *a_prefered_h);
    873     free(reply);
    874 
    875     EPHYR_LOG("leave\n");
    876 }
    877 
    878 
    879 static Bool
    880 ephyrHostXVPutImage(KdScreenInfo * a_info,
    881                     EphyrPortPriv *port_priv,
    882                     int a_image_id,
    883                     int a_drw_x,
    884                     int a_drw_y,
    885                     int a_drw_w,
    886                     int a_drw_h,
    887                     int a_src_x,
    888                     int a_src_y,
    889                     int a_src_w,
    890                     int a_src_h,
    891                     int a_image_width,
    892                     int a_image_height,
    893                     unsigned char *a_buf,
    894                     BoxPtr a_clip_rects, int a_clip_rect_nums)
    895 {
    896     EphyrScrPriv *scrpriv = a_info->driver;
    897     xcb_connection_t *conn = hostx_get_xcbconn();
    898     xcb_gcontext_t gc;
    899     Bool is_ok = TRUE;
    900     xcb_rectangle_t *rects = NULL;
    901     int data_len, width, height;
    902     xcb_xv_query_image_attributes_cookie_t image_attr_cookie;
    903     xcb_xv_query_image_attributes_reply_t *image_attr_reply;
    904 
    905     EPHYR_RETURN_VAL_IF_FAIL(a_buf, FALSE);
    906 
    907     EPHYR_LOG("enter, num_clip_rects: %d\n", a_clip_rect_nums);
    908 
    909     image_attr_cookie = xcb_xv_query_image_attributes(conn,
    910                                                       port_priv->port_number,
    911                                                       a_image_id,
    912                                                       a_image_width,
    913                                                       a_image_height);
    914     image_attr_reply = xcb_xv_query_image_attributes_reply(conn,
    915                                                            image_attr_cookie,
    916                                                            NULL);
    917     if (!image_attr_reply)
    918         goto out;
    919     data_len = image_attr_reply->data_size;
    920     width = image_attr_reply->width;
    921     height = image_attr_reply->height;
    922     free(image_attr_reply);
    923 
    924     gc = xcb_generate_id(conn);
    925     xcb_create_gc(conn, gc, scrpriv->win, 0, NULL);
    926 
    927     if (a_clip_rect_nums) {
    928         int i = 0;
    929         rects = calloc(a_clip_rect_nums, sizeof(xcb_rectangle_t));
    930         for (i=0; i < a_clip_rect_nums; i++) {
    931             rects[i].x = a_clip_rects[i].x1;
    932             rects[i].y = a_clip_rects[i].y1;
    933             rects[i].width = a_clip_rects[i].x2 - a_clip_rects[i].x1;
    934             rects[i].height = a_clip_rects[i].y2 - a_clip_rects[i].y1;
    935             EPHYR_LOG("(x,y,w,h): (%d,%d,%d,%d)\n",
    936                       rects[i].x, rects[i].y, rects[i].width, rects[i].height);
    937         }
    938         xcb_set_clip_rectangles(conn,
    939                                 XCB_CLIP_ORDERING_YX_BANDED,
    940                                 gc,
    941                                 0,
    942                                 0,
    943                                 a_clip_rect_nums,
    944                                 rects);
    945 	free(rects);
    946     }
    947     xcb_xv_put_image(conn,
    948                      port_priv->port_number,
    949                      scrpriv->win,
    950                      gc,
    951                      a_image_id,
    952                      a_src_x, a_src_y, a_src_w, a_src_h,
    953                      a_drw_x, a_drw_y, a_drw_w, a_drw_h,
    954                      width, height,
    955                      data_len, a_buf);
    956     xcb_free_gc(conn, gc);
    957 
    958     is_ok = TRUE;
    959 
    960 out:
    961     EPHYR_LOG("leave\n");
    962     return is_ok;
    963 }
    964 
    965 static int
    966 ephyrPutImage(KdScreenInfo * a_info,
    967               DrawablePtr a_drawable,
    968               short a_src_x,
    969               short a_src_y,
    970               short a_drw_x,
    971               short a_drw_y,
    972               short a_src_w,
    973               short a_src_h,
    974               short a_drw_w,
    975               short a_drw_h,
    976               int a_id,
    977               unsigned char *a_buf,
    978               short a_width,
    979               short a_height,
    980               Bool a_sync, RegionPtr a_clipping_region, void *a_port_priv)
    981 {
    982     EphyrPortPriv *port_priv = a_port_priv;
    983     Bool is_ok = FALSE;
    984     int result = BadImplementation, image_size = 0;
    985 
    986     EPHYR_RETURN_VAL_IF_FAIL(a_info && a_info->pScreen, BadValue);
    987     EPHYR_RETURN_VAL_IF_FAIL(a_drawable, BadValue);
    988 
    989     EPHYR_LOG("enter\n");
    990 
    991     if (!ephyrHostXVPutImage(a_info, port_priv,
    992                              a_id,
    993                              a_drw_x, a_drw_y, a_drw_w, a_drw_h,
    994                              a_src_x, a_src_y, a_src_w, a_src_h,
    995                              a_width, a_height, a_buf,
    996                              RegionRects(a_clipping_region),
    997                              RegionNumRects(a_clipping_region))) {
    998         EPHYR_LOG_ERROR("EphyrHostXVPutImage() failed\n");
    999         goto out;
   1000     }
   1001 
   1002     /*
   1003      * Now save the image so that we can resend it to host it
   1004      * later, in ReputImage.
   1005      */
   1006     if (!ephyrXVPrivGetImageBufSize(port_priv->port_number,
   1007                                     a_id, a_width, a_height, &image_size)) {
   1008         EPHYR_LOG_ERROR("failed to get image size\n");
   1009         /*this is a minor error so we won't get bail out abruptly */
   1010         is_ok = FALSE;
   1011     }
   1012     else {
   1013         is_ok = TRUE;
   1014     }
   1015     if (is_ok) {
   1016         if (!ephyrXVPrivSaveImageToPortPriv(port_priv, a_buf, image_size)) {
   1017             is_ok = FALSE;
   1018         }
   1019         else {
   1020             port_priv->image_id = a_id;
   1021             port_priv->drw_x = a_drw_x;
   1022             port_priv->drw_y = a_drw_y;
   1023             port_priv->drw_w = a_drw_w;
   1024             port_priv->drw_h = a_drw_h;
   1025             port_priv->src_x = a_src_x;
   1026             port_priv->src_y = a_src_y;
   1027             port_priv->src_w = a_src_w;
   1028             port_priv->src_h = a_src_h;
   1029             port_priv->image_width = a_width;
   1030             port_priv->image_height = a_height;
   1031         }
   1032     }
   1033     if (!is_ok) {
   1034         if (port_priv->image_buf) {
   1035             free(port_priv->image_buf);
   1036             port_priv->image_buf = NULL;
   1037             port_priv->image_buf_size = 0;
   1038         }
   1039     }
   1040 
   1041     result = Success;
   1042 
   1043  out:
   1044     EPHYR_LOG("leave\n");
   1045     return result;
   1046 }
   1047 
   1048 static int
   1049 ephyrReputImage(KdScreenInfo * a_info,
   1050                 DrawablePtr a_drawable,
   1051                 short a_drw_x,
   1052                 short a_drw_y, RegionPtr a_clipping_region, void *a_port_priv)
   1053 {
   1054     EphyrPortPriv *port_priv = a_port_priv;
   1055     int result = BadImplementation;
   1056 
   1057     EPHYR_RETURN_VAL_IF_FAIL(a_info->pScreen, FALSE);
   1058     EPHYR_RETURN_VAL_IF_FAIL(a_drawable && port_priv, BadValue);
   1059 
   1060     EPHYR_LOG("enter\n");
   1061 
   1062     if (!port_priv->image_buf_size || !port_priv->image_buf) {
   1063         EPHYR_LOG_ERROR("has null image buf in cache\n");
   1064         goto out;
   1065     }
   1066     if (!ephyrHostXVPutImage(a_info,
   1067                              port_priv,
   1068                              port_priv->image_id,
   1069                              a_drw_x, a_drw_y,
   1070                              port_priv->drw_w, port_priv->drw_h,
   1071                              port_priv->src_x, port_priv->src_y,
   1072                              port_priv->src_w, port_priv->src_h,
   1073                              port_priv->image_width, port_priv->image_height,
   1074                              port_priv->image_buf,
   1075                              RegionRects(a_clipping_region),
   1076                              RegionNumRects(a_clipping_region))) {
   1077         EPHYR_LOG_ERROR("ephyrHostXVPutImage() failed\n");
   1078         goto out;
   1079     }
   1080 
   1081     result = Success;
   1082 
   1083  out:
   1084     EPHYR_LOG("leave\n");
   1085     return result;
   1086 }
   1087 
   1088 static int
   1089 ephyrPutVideo(KdScreenInfo * a_info,
   1090               DrawablePtr a_drawable,
   1091               short a_vid_x, short a_vid_y,
   1092               short a_drw_x, short a_drw_y,
   1093               short a_vid_w, short a_vid_h,
   1094               short a_drw_w, short a_drw_h,
   1095               RegionPtr a_clipping_region, void *a_port_priv)
   1096 {
   1097     EphyrScrPriv *scrpriv = a_info->driver;
   1098     xcb_connection_t *conn = hostx_get_xcbconn();
   1099     xcb_gcontext_t gc;
   1100     EphyrPortPriv *port_priv = a_port_priv;
   1101 
   1102     EPHYR_RETURN_VAL_IF_FAIL(a_info->pScreen, BadValue);
   1103     EPHYR_RETURN_VAL_IF_FAIL(a_drawable && port_priv, BadValue);
   1104 
   1105     EPHYR_LOG("enter\n");
   1106 
   1107     gc = xcb_generate_id(conn);
   1108     xcb_create_gc(conn, gc, scrpriv->win, 0, NULL);
   1109     xcb_xv_put_video(conn, port_priv->port_number,
   1110                      scrpriv->win, gc,
   1111                      a_vid_x, a_vid_y, a_vid_w, a_vid_h,
   1112                      a_drw_x, a_drw_y, a_drw_w, a_drw_h);
   1113     xcb_free_gc(conn, gc);
   1114 
   1115     EPHYR_LOG("leave\n");
   1116     return Success;
   1117 }
   1118 
   1119 static int
   1120 ephyrGetVideo(KdScreenInfo * a_info,
   1121               DrawablePtr a_drawable,
   1122               short a_vid_x, short a_vid_y,
   1123               short a_drw_x, short a_drw_y,
   1124               short a_vid_w, short a_vid_h,
   1125               short a_drw_w, short a_drw_h,
   1126               RegionPtr a_clipping_region, void *a_port_priv)
   1127 {
   1128     EphyrScrPriv *scrpriv = a_info->driver;
   1129     xcb_connection_t *conn = hostx_get_xcbconn();
   1130     xcb_gcontext_t gc;
   1131     EphyrPortPriv *port_priv = a_port_priv;
   1132 
   1133     EPHYR_RETURN_VAL_IF_FAIL(a_info && a_info->pScreen, BadValue);
   1134     EPHYR_RETURN_VAL_IF_FAIL(a_drawable && port_priv, BadValue);
   1135 
   1136     EPHYR_LOG("enter\n");
   1137 
   1138     gc = xcb_generate_id(conn);
   1139     xcb_create_gc(conn, gc, scrpriv->win, 0, NULL);
   1140     xcb_xv_get_video(conn, port_priv->port_number,
   1141                      scrpriv->win, gc,
   1142                      a_vid_x, a_vid_y, a_vid_w, a_vid_h,
   1143                      a_drw_x, a_drw_y, a_drw_w, a_drw_h);
   1144 
   1145     xcb_free_gc(conn, gc);
   1146 
   1147     EPHYR_LOG("leave\n");
   1148     return Success;
   1149 }
   1150 
   1151 static int
   1152 ephyrPutStill(KdScreenInfo * a_info,
   1153               DrawablePtr a_drawable,
   1154               short a_vid_x, short a_vid_y,
   1155               short a_drw_x, short a_drw_y,
   1156               short a_vid_w, short a_vid_h,
   1157               short a_drw_w, short a_drw_h,
   1158               RegionPtr a_clipping_region, void *a_port_priv)
   1159 {
   1160     EphyrScrPriv *scrpriv = a_info->driver;
   1161     xcb_connection_t *conn = hostx_get_xcbconn();
   1162     xcb_gcontext_t gc;
   1163     EphyrPortPriv *port_priv = a_port_priv;
   1164 
   1165     EPHYR_RETURN_VAL_IF_FAIL(a_info && a_info->pScreen, BadValue);
   1166     EPHYR_RETURN_VAL_IF_FAIL(a_drawable && port_priv, BadValue);
   1167 
   1168     EPHYR_LOG("enter\n");
   1169 
   1170     gc = xcb_generate_id(conn);
   1171     xcb_create_gc(conn, gc, scrpriv->win, 0, NULL);
   1172     xcb_xv_put_still(conn, port_priv->port_number,
   1173                      scrpriv->win, gc,
   1174                      a_vid_x, a_vid_y, a_vid_w, a_vid_h,
   1175                      a_drw_x, a_drw_y, a_drw_w, a_drw_h);
   1176     xcb_free_gc(conn, gc);
   1177 
   1178     EPHYR_LOG("leave\n");
   1179     return Success;
   1180 }
   1181 
   1182 static int
   1183 ephyrGetStill(KdScreenInfo * a_info,
   1184               DrawablePtr a_drawable,
   1185               short a_vid_x, short a_vid_y,
   1186               short a_drw_x, short a_drw_y,
   1187               short a_vid_w, short a_vid_h,
   1188               short a_drw_w, short a_drw_h,
   1189               RegionPtr a_clipping_region, void *a_port_priv)
   1190 {
   1191     EphyrScrPriv *scrpriv = a_info->driver;
   1192     xcb_connection_t *conn = hostx_get_xcbconn();
   1193     xcb_gcontext_t gc;
   1194     EphyrPortPriv *port_priv = a_port_priv;
   1195 
   1196     EPHYR_RETURN_VAL_IF_FAIL(a_info && a_info->pScreen, BadValue);
   1197     EPHYR_RETURN_VAL_IF_FAIL(a_drawable && port_priv, BadValue);
   1198 
   1199     EPHYR_LOG("enter\n");
   1200 
   1201     gc = xcb_generate_id(conn);
   1202     xcb_create_gc(conn, gc, scrpriv->win, 0, NULL);
   1203     xcb_xv_get_still(conn, port_priv->port_number,
   1204                      scrpriv->win, gc,
   1205                      a_vid_x, a_vid_y, a_vid_w, a_vid_h,
   1206                      a_drw_x, a_drw_y, a_drw_w, a_drw_h);
   1207     xcb_free_gc(conn, gc);
   1208 
   1209     EPHYR_LOG("leave\n");
   1210     return Success;
   1211 }
   1212 
   1213 static int
   1214 ephyrQueryImageAttributes(KdScreenInfo * a_info,
   1215                           int a_id,
   1216                           unsigned short *a_w,
   1217                           unsigned short *a_h, int *a_pitches, int *a_offsets)
   1218 {
   1219     xcb_connection_t *conn = hostx_get_xcbconn();
   1220     xcb_xv_query_image_attributes_cookie_t cookie;
   1221     xcb_xv_query_image_attributes_reply_t *reply;
   1222     int image_size = 0;
   1223 
   1224     EPHYR_RETURN_VAL_IF_FAIL(a_w && a_h, FALSE);
   1225 
   1226     EPHYR_LOG("enter: dim (%dx%d), pitches: %p, offsets: %p\n",
   1227               *a_w, *a_h, a_pitches, a_offsets);
   1228 
   1229     cookie = xcb_xv_query_image_attributes(conn,
   1230                                            s_base_port_id, a_id,
   1231                                            *a_w, *a_h);
   1232     reply = xcb_xv_query_image_attributes_reply(conn, cookie, NULL);
   1233     if (!reply)
   1234         goto out;
   1235 
   1236     *a_w = reply->width;
   1237     *a_h = reply->height;
   1238     if (a_pitches && a_offsets) {
   1239         memcpy(a_pitches, xcb_xv_query_image_attributes_pitches(reply),
   1240                reply->num_planes << 2);
   1241         memcpy(a_offsets, xcb_xv_query_image_attributes_offsets(reply),
   1242                reply->num_planes << 2);
   1243     }
   1244     image_size = reply->data_size;
   1245 
   1246     free(reply);
   1247 
   1248     EPHYR_LOG("image size: %d, dim (%dx%d)\n", image_size, *a_w, *a_h);
   1249 
   1250  out:
   1251     EPHYR_LOG("leave\n");
   1252     return image_size;
   1253 }