1 /*
2  * Xephyr - A kdrive X server thats 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
adaptor_has_flags(const xcb_xv_adaptor_info_t * adaptor,uint32_t flags)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
ephyrLocalAtomToHost(int a_local_atom,int * a_host_atom)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
ephyrInitVideo(ScreenPtr pScreen)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 *
ephyrXVPrivNew(void)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
ephyrXVPrivDelete(EphyrXVPriv * a_this)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
translate_video_encodings(KdVideoAdaptorPtr adaptor,xcb_xv_adaptor_info_t * host_adaptor)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
translate_xv_attributes(KdVideoAdaptorPtr adaptor,xcb_xv_adaptor_info_t * host_adaptor)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
translate_xv_image_formats(KdVideoAdaptorPtr adaptor,xcb_xv_adaptor_info_t * host_adaptor)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
ephyrXVPrivQueryHostAdaptors(EphyrXVPriv * a_this)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
ephyrXVPrivSetAdaptorsHooks(EphyrXVPriv * a_this)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
ephyrXVPrivRegisterAdaptors(EphyrXVPriv * a_this,ScreenPtr a_screen)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
ephyrXVPrivIsAttrValueValid(XvAttributePtr a_attrs,int a_attrs_len,const char * a_attr_name,int a_attr_value,Bool * a_is_valid)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
ephyrXVPrivGetImageBufSize(int a_port_id,int a_image_id,unsigned short a_width,unsigned short a_height,int * a_size)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
ephyrXVPrivSaveImageToPortPriv(EphyrPortPriv * a_port_priv,const unsigned char * a_image_buf,int a_image_len)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
ephyrStopVideo(KdScreenInfo * a_info,void * a_port_priv,Bool a_exit)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
ephyrSetPortAttribute(KdScreenInfo * a_info,Atom a_attr_name,int a_attr_value,void * a_port_priv)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
ephyrGetPortAttribute(KdScreenInfo * a_screen_info,Atom a_attr_name,int * a_attr_value,void * a_port_priv)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
ephyrQueryBestSize(KdScreenInfo * a_info,Bool a_motion,short a_src_w,short a_src_h,short a_drw_w,short a_drw_h,unsigned int * a_prefered_w,unsigned int * a_prefered_h,void * a_port_priv)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
ephyrHostXVPutImage(KdScreenInfo * a_info,EphyrPortPriv * port_priv,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,BoxPtr a_clip_rects,int a_clip_rect_nums)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
ephyrPutImage(KdScreenInfo * a_info,DrawablePtr a_drawable,short a_src_x,short a_src_y,short a_drw_x,short a_drw_y,short a_src_w,short a_src_h,short a_drw_w,short a_drw_h,int a_id,unsigned char * a_buf,short a_width,short a_height,Bool a_sync,RegionPtr a_clipping_region,void * a_port_priv)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
ephyrReputImage(KdScreenInfo * a_info,DrawablePtr a_drawable,short a_drw_x,short a_drw_y,RegionPtr a_clipping_region,void * a_port_priv)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
ephyrPutVideo(KdScreenInfo * a_info,DrawablePtr a_drawable,short a_vid_x,short a_vid_y,short a_drw_x,short a_drw_y,short a_vid_w,short a_vid_h,short a_drw_w,short a_drw_h,RegionPtr a_clipping_region,void * a_port_priv)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
ephyrGetVideo(KdScreenInfo * a_info,DrawablePtr a_drawable,short a_vid_x,short a_vid_y,short a_drw_x,short a_drw_y,short a_vid_w,short a_vid_h,short a_drw_w,short a_drw_h,RegionPtr a_clipping_region,void * a_port_priv)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
ephyrPutStill(KdScreenInfo * a_info,DrawablePtr a_drawable,short a_vid_x,short a_vid_y,short a_drw_x,short a_drw_y,short a_vid_w,short a_vid_h,short a_drw_w,short a_drw_h,RegionPtr a_clipping_region,void * a_port_priv)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
ephyrGetStill(KdScreenInfo * a_info,DrawablePtr a_drawable,short a_vid_x,short a_vid_y,short a_drw_x,short a_drw_y,short a_vid_w,short a_vid_h,short a_drw_w,short a_drw_h,RegionPtr a_clipping_region,void * a_port_priv)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
ephyrQueryImageAttributes(KdScreenInfo * a_info,int a_id,unsigned short * a_w,unsigned short * a_h,int * a_pitches,int * a_offsets)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 }
1254