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