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 "ephyrlog.h" 35#include "kdrive.h" 36#include "kxv.h" 37#include "ephyr.h" 38#include "hostx.h" 39#include "ephyrhostvideo.h" 40 41struct _EphyrXVPriv { 42 EphyrHostXVAdaptorArray *host_adaptors ; 43 KdVideoAdaptorPtr adaptors ; 44 int num_adaptors ; 45}; 46typedef struct _EphyrXVPriv EphyrXVPriv ; 47 48struct _EphyrPortPriv { 49 int port_number ; 50 KdVideoAdaptorPtr current_adaptor ; 51 EphyrXVPriv *xv_priv; 52 unsigned char *image_buf ; 53 int image_buf_size ; 54 int image_id ; 55 int drw_x, drw_y, drw_w, drw_h ; 56 int src_x, src_y, src_w, src_h ; 57 int image_width, image_height ; 58}; 59typedef struct _EphyrPortPriv EphyrPortPriv ; 60 61static Bool DoSimpleClip (BoxPtr a_dst_drw, 62 BoxPtr a_clipper, 63 BoxPtr a_result) ; 64 65static Bool ephyrLocalAtomToHost (int a_local_atom, int *a_host_atom) ; 66 67/* 68static Bool ephyrHostAtomToLocal (int a_host_atom, int *a_local_atom) ; 69*/ 70 71static EphyrXVPriv* ephyrXVPrivNew (void) ; 72static void ephyrXVPrivDelete (EphyrXVPriv *a_this) ; 73static Bool ephyrXVPrivQueryHostAdaptors (EphyrXVPriv *a_this) ; 74static Bool ephyrXVPrivSetAdaptorsHooks (EphyrXVPriv *a_this) ; 75static Bool ephyrXVPrivRegisterAdaptors (EphyrXVPriv *a_this, 76 ScreenPtr a_screen) ; 77 78static Bool ephyrXVPrivIsAttrValueValid (KdAttributePtr a_attrs, 79 int a_attrs_len, 80 const char *a_attr_name, 81 int a_attr_value, 82 Bool *a_is_valid) ; 83 84static Bool ephyrXVPrivGetImageBufSize (int a_port_id, 85 int a_image_id, 86 unsigned short a_width, 87 unsigned short a_height, 88 int *a_size) ; 89 90static Bool ephyrXVPrivSaveImageToPortPriv (EphyrPortPriv *a_port_priv, 91 const unsigned char *a_image, 92 int a_image_len) ; 93 94static void ephyrStopVideo (KdScreenInfo *a_info, 95 pointer a_xv_priv, 96 Bool a_exit); 97 98static int ephyrSetPortAttribute (KdScreenInfo *a_info, 99 Atom a_attr_name, 100 int a_attr_value, 101 pointer a_port_priv); 102 103static int ephyrGetPortAttribute (KdScreenInfo *a_screen_info, 104 Atom a_attr_name, 105 int *a_attr_value, 106 pointer a_port_priv); 107 108static void ephyrQueryBestSize (KdScreenInfo *a_info, 109 Bool a_motion, 110 short a_src_w, 111 short a_src_h, 112 short a_drw_w, 113 short a_drw_h, 114 unsigned int *a_prefered_w, 115 unsigned int *a_prefered_h, 116 pointer a_port_priv); 117 118static int ephyrPutImage (KdScreenInfo *a_info, 119 DrawablePtr a_drawable, 120 short a_src_x, 121 short a_src_y, 122 short a_drw_x, 123 short a_drw_y, 124 short a_src_w, 125 short a_src_h, 126 short a_drw_w, 127 short a_drw_h, 128 int a_id, 129 unsigned char *a_buf, 130 short a_width, 131 short a_height, 132 Bool a_sync, 133 RegionPtr a_clipping_region, 134 pointer a_port_priv); 135 136static int ephyrReputImage (KdScreenInfo *a_info, 137 DrawablePtr a_drawable, 138 short a_drw_x, 139 short a_drw_y, 140 RegionPtr a_clipping_region, 141 pointer a_port_priv) ; 142 143static int ephyrPutVideo (KdScreenInfo *a_info, 144 DrawablePtr a_drawable, 145 short a_vid_x, short a_vid_y, 146 short a_drw_x, short a_drw_y, 147 short a_vid_w, short a_vid_h, 148 short a_drw_w, short a_drw_h, 149 RegionPtr a_clip_region, 150 pointer a_port_priv) ; 151 152static int ephyrGetVideo (KdScreenInfo *a_info, 153 DrawablePtr a_drawable, 154 short a_vid_x, short a_vid_y, 155 short a_drw_x, short a_drw_y, 156 short a_vid_w, short a_vid_h, 157 short a_drw_w, short a_drw_h, 158 RegionPtr a_clip_region, 159 pointer a_port_priv) ; 160 161static int ephyrPutStill (KdScreenInfo *a_info, 162 DrawablePtr a_drawable, 163 short a_vid_x, short a_vid_y, 164 short a_drw_x, short a_drw_y, 165 short a_vid_w, short a_vid_h, 166 short a_drw_w, short a_drw_h, 167 RegionPtr a_clip_region, 168 pointer a_port_priv) ; 169 170static int ephyrGetStill (KdScreenInfo *a_info, 171 DrawablePtr a_drawable, 172 short a_vid_x, short a_vid_y, 173 short a_drw_x, short a_drw_y, 174 short a_vid_w, short a_vid_h, 175 short a_drw_w, short a_drw_h, 176 RegionPtr a_clip_region, 177 pointer a_port_priv) ; 178 179static int ephyrQueryImageAttributes (KdScreenInfo *a_info, 180 int a_id, 181 unsigned short *a_w, 182 unsigned short *a_h, 183 int *a_pitches, 184 int *a_offsets); 185static int s_base_port_id ; 186 187/************** 188 * <helpers> 189 * ************/ 190 191static Bool 192DoSimpleClip (BoxPtr a_dst_box, 193 BoxPtr a_clipper, 194 BoxPtr a_result) 195{ 196 BoxRec dstClippedBox ; 197 198 EPHYR_RETURN_VAL_IF_FAIL (a_dst_box && a_clipper && a_result, FALSE) ; 199 200 /* 201 * setup the clipbox inside the destination. 202 */ 203 dstClippedBox.x1 = a_dst_box->x1 ; 204 dstClippedBox.x2 = a_dst_box->x2 ; 205 dstClippedBox.y1 = a_dst_box->y1 ; 206 dstClippedBox.y2 = a_dst_box->y2 ; 207 208 /* 209 * if the cliper leftmost edge is inside 210 * the destination area then the leftmost edge of the resulting 211 * clipped box is the leftmost edge of the cliper. 212 */ 213 if (a_clipper->x1 > dstClippedBox.x1) 214 dstClippedBox.x1 = a_clipper->x1 ; 215 216 /* 217 * if the cliper top edge is inside the destination area 218 * then the bottom horizontal edge of the resulting clipped box 219 * is the bottom edge of the cliper 220 */ 221 if (a_clipper->y1 > dstClippedBox.y1) 222 dstClippedBox.y1 = a_clipper->y1 ; 223 224 /*ditto for right edge*/ 225 if (a_clipper->x2 < dstClippedBox.x2) 226 dstClippedBox.x2 = a_clipper->x2 ; 227 228 /*ditto for bottom edge*/ 229 if (a_clipper->y2 < dstClippedBox.y2) 230 dstClippedBox.y2 = a_clipper->y2 ; 231 232 memcpy (a_result, &dstClippedBox, sizeof (dstClippedBox)) ; 233 return TRUE ; 234} 235 236static Bool 237ephyrLocalAtomToHost (int a_local_atom, int *a_host_atom) 238{ 239 const char *atom_name=NULL; 240 int host_atom=None ; 241 242 EPHYR_RETURN_VAL_IF_FAIL (a_host_atom, FALSE) ; 243 244 if (!ValidAtom (a_local_atom)) 245 return FALSE ; 246 247 atom_name = NameForAtom (a_local_atom) ; 248 249 if (!atom_name) 250 return FALSE ; 251 252 if (!ephyrHostGetAtom (atom_name, FALSE, &host_atom) || host_atom == None) { 253 EPHYR_LOG_ERROR ("no atom for string %s defined in host X\n", 254 atom_name) ; 255 return FALSE ; 256 } 257 *a_host_atom = host_atom ; 258 return TRUE ; 259} 260 261/* 262 Not used yed. 263static Bool 264ephyrHostAtomToLocal (int a_host_atom, int *a_local_atom) 265{ 266 Bool is_ok=FALSE ; 267 char *atom_name=NULL ; 268 int atom=None ; 269 270 EPHYR_RETURN_VAL_IF_FAIL (a_local_atom, FALSE) ; 271 272 atom_name = ephyrHostGetAtomName (a_host_atom) ; 273 if (!atom_name) 274 goto out ; 275 276 atom = MakeAtom (atom_name, strlen (atom_name), TRUE) ; 277 if (atom == None) 278 goto out ; 279 280 *a_local_atom = atom ; 281 is_ok = TRUE ; 282 283out: 284 if (atom_name) { 285 ephyrHostFree (atom_name) ; 286 } 287 return is_ok ; 288} 289*/ 290 291/************** 292 *</helpers> 293 * ************/ 294 295Bool 296ephyrInitVideo (ScreenPtr pScreen) 297{ 298 Bool is_ok = FALSE ; 299 KdScreenPriv(pScreen); 300 KdScreenInfo *screen = pScreenPriv->screen; 301 static EphyrXVPriv *xv_priv; 302 303 EPHYR_LOG ("enter\n") ; 304 305 if (screen->fb.bitsPerPixel == 8) { 306 EPHYR_LOG_ERROR ("8 bits depth not supported\n") ; 307 return FALSE ; 308 } 309 310 if (!xv_priv) { 311 xv_priv = ephyrXVPrivNew () ; 312 } 313 if (!xv_priv) { 314 EPHYR_LOG_ERROR ("failed to create xv_priv\n") ; 315 goto out ; 316 } 317 318 if (!ephyrXVPrivRegisterAdaptors (xv_priv, pScreen)) { 319 EPHYR_LOG_ERROR ("failed to register adaptors\n") ; 320 goto out ; 321 } 322 is_ok = TRUE ; 323 324out: 325 return is_ok ; 326} 327 328static EphyrXVPriv* 329ephyrXVPrivNew (void) 330{ 331 EphyrXVPriv *xv_priv=NULL ; 332 333 EPHYR_LOG ("enter\n") ; 334 335 xv_priv = calloc(1, sizeof (EphyrXVPriv)) ; 336 if (!xv_priv) { 337 EPHYR_LOG_ERROR ("failed to create EphyrXVPriv\n") ; 338 goto error ; 339 } 340 341 ephyrHostXVInit () ; 342 343 if (!ephyrXVPrivQueryHostAdaptors (xv_priv)) { 344 EPHYR_LOG_ERROR ("failed to query the host x for xv properties\n") ; 345 goto error ; 346 } 347 if (!ephyrXVPrivSetAdaptorsHooks (xv_priv)) { 348 EPHYR_LOG_ERROR ("failed to set xv_priv hooks\n") ; 349 goto error ; 350 } 351 352 EPHYR_LOG ("leave\n") ; 353 return xv_priv ; 354 355error: 356 if (xv_priv) { 357 ephyrXVPrivDelete (xv_priv) ; 358 xv_priv = NULL ; 359 } 360 return NULL ; 361} 362 363static void 364ephyrXVPrivDelete (EphyrXVPriv *a_this) 365{ 366 EPHYR_LOG ("enter\n") ; 367 368 if (!a_this) 369 return ; 370 if (a_this->host_adaptors) { 371 ephyrHostXVAdaptorArrayDelete (a_this->host_adaptors) ; 372 a_this->host_adaptors = NULL ; 373 } 374 free(a_this->adaptors) ; 375 a_this->adaptors = NULL ; 376 free(a_this) ; 377 EPHYR_LOG ("leave\n") ; 378} 379 380static KdVideoEncodingPtr 381videoEncodingDup (EphyrHostEncoding *a_encodings, 382 int a_num_encodings) 383{ 384 KdVideoEncodingPtr result = NULL ; 385 int i=0 ; 386 387 EPHYR_RETURN_VAL_IF_FAIL (a_encodings && a_num_encodings, NULL) ; 388 389 result = calloc(a_num_encodings, sizeof (KdVideoEncodingRec)) ; 390 for (i=0 ; i < a_num_encodings; i++) { 391 result[i].id = a_encodings[i].id ; 392 result[i].name = strdup (a_encodings[i].name) ; 393 result[i].width = a_encodings[i].width ; 394 result[i].height = a_encodings[i].height ; 395 result[i].rate.numerator = a_encodings[i].rate.numerator ; 396 result[i].rate.denominator = a_encodings[i].rate.denominator ; 397 } 398 return result ; 399} 400 401static KdAttributePtr 402portAttributesDup (EphyrHostAttribute *a_encodings, 403 int a_num_encodings) 404{ 405 int i=0 ; 406 KdAttributePtr result=NULL ; 407 408 EPHYR_RETURN_VAL_IF_FAIL (a_encodings && a_num_encodings, NULL) ; 409 410 result = calloc(a_num_encodings, sizeof (KdAttributeRec)) ; 411 if (!result) { 412 EPHYR_LOG_ERROR ("failed to allocate attributes\n") ; 413 return NULL ; 414 } 415 for (i=0; i < a_num_encodings; i++) { 416 result[i].flags = a_encodings[i].flags ; 417 result[i].min_value = a_encodings[i].min_value ; 418 result[i].max_value = a_encodings[i].max_value ; 419 result[i].name = strdup (a_encodings[i].name) ; 420 } 421 return result ; 422} 423 424static Bool 425ephyrXVPrivQueryHostAdaptors (EphyrXVPriv *a_this) 426{ 427 EphyrHostXVAdaptor *cur_host_adaptor=NULL ; 428 EphyrHostVideoFormat *video_formats=NULL ; 429 EphyrHostEncoding *encodings=NULL ; 430 EphyrHostAttribute *attributes=NULL ; 431 EphyrHostImageFormat *image_formats=NULL ; 432 int num_video_formats=0, base_port_id=0, 433 num_attributes=0, num_formats=0, i=0, 434 port_priv_offset=0; 435 unsigned num_encodings=0 ; 436 Bool is_ok = FALSE ; 437 438 EPHYR_RETURN_VAL_IF_FAIL (a_this, FALSE) ; 439 440 EPHYR_LOG ("enter\n") ; 441 442 if (!ephyrHostXVQueryAdaptors (&a_this->host_adaptors)) { 443 EPHYR_LOG_ERROR ("failed to query host adaptors\n") ; 444 goto out ; 445 } 446 if (a_this->host_adaptors) 447 a_this->num_adaptors = 448 ephyrHostXVAdaptorArrayGetSize (a_this->host_adaptors) ; 449 if (a_this->num_adaptors < 0) { 450 EPHYR_LOG_ERROR ("failed to get number of host adaptors\n") ; 451 goto out ; 452 } 453 EPHYR_LOG ("host has %d adaptors\n", a_this->num_adaptors) ; 454 /* 455 * copy what we can from adaptors into a_this->adaptors 456 */ 457 if (a_this->num_adaptors) { 458 a_this->adaptors = calloc(a_this->num_adaptors, 459 sizeof (KdVideoAdaptorRec)) ; 460 if (!a_this->adaptors) { 461 EPHYR_LOG_ERROR ("failed to create internal adaptors\n") ; 462 goto out ; 463 } 464 } 465 for (i=0; i < a_this->num_adaptors; i++) { 466 int j=0 ; 467 cur_host_adaptor = 468 ephyrHostXVAdaptorArrayAt (a_this->host_adaptors, i) ; 469 if (!cur_host_adaptor) 470 continue ; 471 a_this->adaptors[i].nPorts = 472 ephyrHostXVAdaptorGetNbPorts (cur_host_adaptor) ; 473 if (a_this->adaptors[i].nPorts <=0) { 474 EPHYR_LOG_ERROR ("Could not find any port of adaptor %d\n", i) ; 475 continue ; 476 } 477 a_this->adaptors[i].type = 478 ephyrHostXVAdaptorGetType (cur_host_adaptor) ; 479 a_this->adaptors[i].type |= XvWindowMask ; 480 a_this->adaptors[i].flags = 481 VIDEO_OVERLAID_IMAGES | VIDEO_CLIP_TO_VIEWPORT; 482 if (ephyrHostXVAdaptorGetName (cur_host_adaptor)) 483 a_this->adaptors[i].name = 484 strdup (ephyrHostXVAdaptorGetName (cur_host_adaptor)) ; 485 else 486 a_this->adaptors[i].name = strdup ("Xephyr Video Overlay"); 487 base_port_id = ephyrHostXVAdaptorGetFirstPortID (cur_host_adaptor) ; 488 if (base_port_id < 0) { 489 EPHYR_LOG_ERROR ("failed to get port id for adaptor %d\n", i) ; 490 continue ; 491 } 492 if (!s_base_port_id) 493 s_base_port_id = base_port_id ; 494 495 if (!ephyrHostXVQueryEncodings (base_port_id, 496 &encodings, 497 &num_encodings)) { 498 EPHYR_LOG_ERROR ("failed to get encodings for port port id %d," 499 " adaptors %d\n", 500 base_port_id, i) ; 501 continue ; 502 } 503 a_this->adaptors[i].nEncodings = num_encodings ; 504 a_this->adaptors[i].pEncodings = 505 videoEncodingDup (encodings, num_encodings) ; 506 video_formats = (EphyrHostVideoFormat*) 507 ephyrHostXVAdaptorGetVideoFormats (cur_host_adaptor, 508 &num_video_formats); 509 a_this->adaptors[i].pFormats = (KdVideoFormatPtr) video_formats ; 510 a_this->adaptors[i].nFormats = num_video_formats ; 511 /* got a_this->adaptors[i].nPorts already 512 a_this->adaptors[i].nPorts = 513 ephyrHostXVAdaptorGetNbPorts (cur_host_adaptor) ; 514 */ 515 a_this->adaptors[i].pPortPrivates = 516 calloc(a_this->adaptors[i].nPorts, 517 sizeof (DevUnion) + sizeof (EphyrPortPriv)) ; 518 port_priv_offset = a_this->adaptors[i].nPorts; 519 for (j=0; j < a_this->adaptors[i].nPorts; j++) { 520 EphyrPortPriv *port_privs_base = 521 (EphyrPortPriv*)&a_this->adaptors[i].pPortPrivates[port_priv_offset]; 522 EphyrPortPriv *port_priv = &port_privs_base[j] ; 523 port_priv->port_number = base_port_id + j; 524 port_priv->current_adaptor = &a_this->adaptors[i] ; 525 port_priv->xv_priv = a_this ; 526 a_this->adaptors[i].pPortPrivates[j].ptr = port_priv; 527 } 528 if (!ephyrHostXVQueryPortAttributes (base_port_id, 529 &attributes, 530 &num_attributes)) { 531 EPHYR_LOG_ERROR ("failed to get port attribute " 532 "for adaptor %d\n", i) ; 533 continue ; 534 } 535 a_this->adaptors[i].pAttributes = 536 portAttributesDup (attributes, num_attributes); 537 a_this->adaptors[i].nAttributes = num_attributes ; 538 /*make sure atoms of attrs names are created in xephyr*/ 539 for (j=0; j < a_this->adaptors[i].nAttributes; j++) { 540 if (a_this->adaptors[i].pAttributes[j].name) 541 MakeAtom (a_this->adaptors[i].pAttributes[j].name, 542 strlen (a_this->adaptors[i].pAttributes[j].name), 543 TRUE) ; 544 } 545 if (!ephyrHostXVQueryImageFormats (base_port_id, 546 &image_formats, 547 &num_formats)) { 548 EPHYR_LOG_ERROR ("failed to get image formats " 549 "for adaptor %d\n", i) ; 550 continue ; 551 } 552 a_this->adaptors[i].pImages = (KdImagePtr) image_formats ; 553 a_this->adaptors[i].nImages = num_formats ; 554 } 555 is_ok = TRUE ; 556 557out: 558 if (encodings) { 559 ephyrHostEncodingsDelete (encodings, num_encodings) ; 560 encodings = NULL ; 561 } 562 if (attributes) { 563 ephyrHostAttributesDelete (attributes) ; 564 attributes = NULL ; 565 } 566 EPHYR_LOG ("leave\n") ; 567 return is_ok ; 568} 569 570static Bool 571ephyrXVPrivSetAdaptorsHooks (EphyrXVPriv *a_this) 572{ 573 int i=0 ; 574 Bool has_it=FALSE ; 575 EphyrHostXVAdaptor *cur_host_adaptor=NULL ; 576 577 EPHYR_RETURN_VAL_IF_FAIL (a_this, FALSE) ; 578 579 EPHYR_LOG ("enter\n") ; 580 581 for (i=0; i < a_this->num_adaptors; i++) { 582 a_this->adaptors[i].ReputImage = ephyrReputImage ; 583 a_this->adaptors[i].StopVideo = ephyrStopVideo ; 584 a_this->adaptors[i].SetPortAttribute = ephyrSetPortAttribute ; 585 a_this->adaptors[i].GetPortAttribute = ephyrGetPortAttribute ; 586 a_this->adaptors[i].QueryBestSize = ephyrQueryBestSize ; 587 a_this->adaptors[i].QueryImageAttributes = ephyrQueryImageAttributes ; 588 589 cur_host_adaptor = 590 ephyrHostXVAdaptorArrayAt (a_this->host_adaptors, i) ; 591 if (!cur_host_adaptor) { 592 EPHYR_LOG_ERROR ("failed to get host adaptor at index %d\n", i) ; 593 continue ; 594 } 595 has_it = FALSE ; 596 if (!ephyrHostXVAdaptorHasPutImage (cur_host_adaptor, &has_it)) { 597 EPHYR_LOG_ERROR ("error\n") ; 598 } 599 if (has_it) { 600 a_this->adaptors[i].PutImage = ephyrPutImage; 601 } 602 603 has_it = FALSE ; 604 if (!ephyrHostXVAdaptorHasPutVideo (cur_host_adaptor, &has_it)) { 605 EPHYR_LOG_ERROR ("error\n") ; 606 } 607 if (has_it) { 608 a_this->adaptors[i].PutVideo = ephyrPutVideo; 609 } 610 611 has_it = FALSE ; 612 if (!ephyrHostXVAdaptorHasGetVideo (cur_host_adaptor, &has_it)) { 613 EPHYR_LOG_ERROR ("error\n") ; 614 } 615 if (has_it) { 616 a_this->adaptors[i].GetVideo = ephyrGetVideo; 617 } 618 619 has_it = FALSE ; 620 if (!ephyrHostXVAdaptorHasPutStill (cur_host_adaptor, &has_it)) { 621 EPHYR_LOG_ERROR ("error\n") ; 622 } 623 if (has_it) { 624 a_this->adaptors[i].PutStill = ephyrPutStill; 625 } 626 627 has_it = FALSE ; 628 if (!ephyrHostXVAdaptorHasGetStill (cur_host_adaptor, &has_it)) { 629 EPHYR_LOG_ERROR ("error\n") ; 630 } 631 if (has_it) { 632 a_this->adaptors[i].GetStill = ephyrGetStill; 633 } 634 } 635 EPHYR_LOG ("leave\n") ; 636 return TRUE ; 637} 638 639static Bool 640ephyrXVPrivRegisterAdaptors (EphyrXVPriv *a_this, 641 ScreenPtr a_screen) 642{ 643 KdScreenPriv(a_screen); 644 KdScreenInfo *screen = pScreenPriv->screen; 645 Bool is_ok = FALSE ; 646 KdVideoAdaptorPtr *adaptors=NULL, *registered_adaptors=NULL ; 647 int num_registered_adaptors=0, i=0, num_adaptors=0 ; 648 649 EPHYR_RETURN_VAL_IF_FAIL (a_this && a_screen, FALSE) ; 650 651 EPHYR_LOG ("enter\n") ; 652 653 if (!a_this->num_adaptors) 654 goto out ; 655 num_registered_adaptors = 656 KdXVListGenericAdaptors (screen, ®istered_adaptors); 657 658 num_adaptors = num_registered_adaptors + a_this->num_adaptors ; 659 adaptors = calloc(num_adaptors, sizeof (KdVideoAdaptorPtr)) ; 660 if (!adaptors) { 661 EPHYR_LOG_ERROR ("failed to allocate adaptors tab\n") ; 662 goto out ; 663 } 664 memmove (adaptors, registered_adaptors, num_registered_adaptors) ; 665 for (i=0 ; i < a_this->num_adaptors; i++) { 666 *(adaptors + num_registered_adaptors + i) = &a_this->adaptors[i] ; 667 } 668 if (!KdXVScreenInit (a_screen, adaptors, num_adaptors)) { 669 EPHYR_LOG_ERROR ("failed to register adaptors\n"); 670 goto out ; 671 } 672 EPHYR_LOG ("there are %d registered adaptors\n", num_adaptors) ; 673 is_ok = TRUE ; 674 675out: 676 free(registered_adaptors) ; 677 registered_adaptors = NULL ; 678 free(adaptors) ; 679 adaptors = NULL ; 680 681 EPHYR_LOG ("leave\n") ; 682 return is_ok ; 683} 684 685static Bool 686ephyrXVPrivIsAttrValueValid (KdAttributePtr a_attrs, 687 int a_attrs_len, 688 const char *a_attr_name, 689 int a_attr_value, 690 Bool *a_is_valid) 691{ 692 int i=0 ; 693 694 EPHYR_RETURN_VAL_IF_FAIL (a_attrs && a_attr_name && a_is_valid, 695 FALSE) ; 696 697 for (i=0; i < a_attrs_len; i++) { 698 if (a_attrs[i].name && strcmp (a_attrs[i].name, a_attr_name)) 699 continue ; 700 if (a_attrs[i].min_value > a_attr_value || 701 a_attrs[i].max_value < a_attr_value) { 702 *a_is_valid = FALSE ; 703 EPHYR_LOG_ERROR ("attribute was not valid\n" 704 "value:%d. min:%d. max:%d\n", 705 a_attr_value, 706 a_attrs[i].min_value, 707 a_attrs[i].max_value) ; 708 } else { 709 *a_is_valid = TRUE ; 710 } 711 return TRUE ; 712 } 713 return FALSE ; 714} 715 716static Bool 717ephyrXVPrivGetImageBufSize (int a_port_id, 718 int a_image_id, 719 unsigned short a_width, 720 unsigned short a_height, 721 int *a_size) 722{ 723 Bool is_ok=FALSE ; 724 unsigned short width=a_width, height=a_height ; 725 726 EPHYR_RETURN_VAL_IF_FAIL (a_size, FALSE) ; 727 728 EPHYR_LOG ("enter\n") ; 729 730 if (!ephyrHostXVQueryImageAttributes (a_port_id, a_image_id, 731 &width, &height, a_size, NULL, NULL)) { 732 EPHYR_LOG_ERROR ("failed to get image attributes\n") ; 733 goto out ; 734 } 735 is_ok = TRUE ; 736 737out: 738 EPHYR_LOG ("leave\n") ; 739 return is_ok ; 740} 741 742static Bool 743ephyrXVPrivSaveImageToPortPriv (EphyrPortPriv *a_port_priv, 744 const unsigned char *a_image_buf, 745 int a_image_len) 746{ 747 Bool is_ok=FALSE ; 748 749 EPHYR_LOG ("enter\n") ; 750 751 if (a_port_priv->image_buf_size < a_image_len) { 752 unsigned char *buf=NULL ; 753 buf = realloc (a_port_priv->image_buf, a_image_len) ; 754 if (!buf) { 755 EPHYR_LOG_ERROR ("failed to realloc image buffer\n") ; 756 goto out ; 757 } 758 a_port_priv->image_buf = buf ; 759 a_port_priv->image_buf_size = a_image_len; 760 } 761 memmove (a_port_priv->image_buf, a_image_buf, a_image_len) ; 762 is_ok = TRUE ; 763 764out: 765 return is_ok ; 766 EPHYR_LOG ("leave\n") ; 767} 768 769static void 770ephyrStopVideo (KdScreenInfo *a_info, pointer a_port_priv, Bool a_exit) 771{ 772 EphyrPortPriv *port_priv = a_port_priv ; 773 774 EPHYR_RETURN_IF_FAIL (a_info && a_info->pScreen) ; 775 EPHYR_RETURN_IF_FAIL (port_priv) ; 776 777 EPHYR_LOG ("enter\n") ; 778 if (!ephyrHostXVStopVideo (a_info->pScreen->myNum, 779 port_priv->port_number)) { 780 EPHYR_LOG_ERROR ("XvStopVideo() failed\n") ; 781 } 782 EPHYR_LOG ("leave\n") ; 783} 784 785static int 786ephyrSetPortAttribute (KdScreenInfo *a_info, 787 Atom a_attr_name, 788 int a_attr_value, 789 pointer a_port_priv) 790{ 791 int res=Success, host_atom=0 ; 792 EphyrPortPriv *port_priv = a_port_priv ; 793 Bool is_attr_valid=FALSE ; 794 795 EPHYR_RETURN_VAL_IF_FAIL (port_priv, BadMatch) ; 796 EPHYR_RETURN_VAL_IF_FAIL (port_priv->current_adaptor, BadMatch) ; 797 EPHYR_RETURN_VAL_IF_FAIL (port_priv->current_adaptor->pAttributes, 798 BadMatch) ; 799 EPHYR_RETURN_VAL_IF_FAIL (port_priv->current_adaptor->nAttributes, 800 BadMatch) ; 801 EPHYR_RETURN_VAL_IF_FAIL (ValidAtom (a_attr_name), BadMatch) ; 802 803 EPHYR_LOG ("enter, portnum:%d, atomid:%d, attr_name:%s, attr_val:%d\n", 804 port_priv->port_number, 805 (int)a_attr_name, 806 NameForAtom (a_attr_name), 807 a_attr_value) ; 808 809 if (!ephyrLocalAtomToHost (a_attr_name, &host_atom)) { 810 EPHYR_LOG_ERROR ("failed to convert local atom to host atom\n") ; 811 res = BadMatch ; 812 goto out ; 813 } 814 815 if (!ephyrXVPrivIsAttrValueValid (port_priv->current_adaptor->pAttributes, 816 port_priv->current_adaptor->nAttributes, 817 NameForAtom (a_attr_name), 818 a_attr_value, 819 &is_attr_valid)) { 820 EPHYR_LOG_ERROR ("failed to validate attribute %s\n", 821 NameForAtom (a_attr_name)) ; 822 /* 823 res = BadMatch ; 824 goto out ; 825 */ 826 } 827 if (!is_attr_valid) { 828 EPHYR_LOG_ERROR ("attribute %s is not valid\n", 829 NameForAtom (a_attr_name)) ; 830 /* 831 res = BadMatch ; 832 goto out ; 833 */ 834 } 835 836 if (!ephyrHostXVSetPortAttribute (port_priv->port_number, 837 host_atom, 838 a_attr_value)) { 839 EPHYR_LOG_ERROR ("failed to set port attribute\n") ; 840 res = BadMatch ; 841 goto out ; 842 } 843 844 res = Success ; 845out: 846 EPHYR_LOG ("leave\n") ; 847 return res ; 848} 849 850static int 851ephyrGetPortAttribute (KdScreenInfo *a_screen_info, 852 Atom a_attr_name, 853 int *a_attr_value, 854 pointer a_port_priv) 855{ 856 int res=Success, host_atom=0 ; 857 EphyrPortPriv *port_priv = a_port_priv ; 858 859 EPHYR_RETURN_VAL_IF_FAIL (port_priv, BadMatch) ; 860 EPHYR_RETURN_VAL_IF_FAIL (ValidAtom (a_attr_name), BadMatch) ; 861 862 EPHYR_LOG ("enter, portnum:%d, atomid:%d, attr_name:%s\n", 863 port_priv->port_number, 864 (int)a_attr_name, 865 NameForAtom (a_attr_name)) ; 866 867 if (!ephyrLocalAtomToHost (a_attr_name, &host_atom)) { 868 EPHYR_LOG_ERROR ("failed to convert local atom to host atom\n") ; 869 res = BadMatch ; 870 goto out ; 871 } 872 873 if (!ephyrHostXVGetPortAttribute (port_priv->port_number, 874 host_atom, 875 a_attr_value)) { 876 EPHYR_LOG_ERROR ("failed to get port attribute\n") ; 877 res = BadMatch ; 878 goto out ; 879 } 880 881 res = Success ; 882out: 883 EPHYR_LOG ("leave\n") ; 884 return res ; 885} 886 887static void 888ephyrQueryBestSize (KdScreenInfo *a_info, 889 Bool a_motion, 890 short a_src_w, 891 short a_src_h, 892 short a_drw_w, 893 short a_drw_h, 894 unsigned int *a_prefered_w, 895 unsigned int *a_prefered_h, 896 pointer a_port_priv) 897{ 898 int res=0 ; 899 EphyrPortPriv *port_priv = a_port_priv ; 900 901 EPHYR_RETURN_IF_FAIL (port_priv) ; 902 903 EPHYR_LOG ("enter\n") ; 904 res = ephyrHostXVQueryBestSize (port_priv->port_number, 905 a_motion, 906 a_src_w, a_src_h, 907 a_drw_w, a_drw_h, 908 a_prefered_w, a_prefered_h) ; 909 if (!res) { 910 EPHYR_LOG_ERROR ("Failed to query best size\n") ; 911 } 912 EPHYR_LOG ("leave\n") ; 913} 914 915static int 916ephyrPutImage (KdScreenInfo *a_info, 917 DrawablePtr a_drawable, 918 short a_src_x, 919 short a_src_y, 920 short a_drw_x, 921 short a_drw_y, 922 short a_src_w, 923 short a_src_h, 924 short a_drw_w, 925 short a_drw_h, 926 int a_id, 927 unsigned char *a_buf, 928 short a_width, 929 short a_height, 930 Bool a_sync, 931 RegionPtr a_clipping_region, 932 pointer a_port_priv) 933{ 934 EphyrPortPriv *port_priv = a_port_priv ; 935 Bool is_ok=FALSE ; 936 int result=BadImplementation, image_size=0 ; 937 938 EPHYR_RETURN_VAL_IF_FAIL (a_info && a_info->pScreen, BadValue) ; 939 EPHYR_RETURN_VAL_IF_FAIL (a_drawable, BadValue) ; 940 941 EPHYR_LOG ("enter\n") ; 942 943 if (!ephyrHostXVPutImage (a_info->pScreen->myNum, 944 port_priv->port_number, 945 a_id, 946 a_drw_x, a_drw_y, a_drw_w, a_drw_h, 947 a_src_x, a_src_y, a_src_w, a_src_h, 948 a_width, a_height, a_buf, 949 (EphyrHostBox*)RegionRects (a_clipping_region), 950 RegionNumRects (a_clipping_region))) { 951 EPHYR_LOG_ERROR ("EphyrHostXVPutImage() failed\n") ; 952 goto out ; 953 } 954 955 /* 956 * Now save the image so that we can resend it to host it 957 * later, in ReputImage. 958 */ 959 if (!ephyrXVPrivGetImageBufSize (port_priv->port_number, 960 a_id, a_width, a_height, &image_size)) { 961 EPHYR_LOG_ERROR ("failed to get image size\n") ; 962 /*this is a minor error so we won't get bail out abruptly*/ 963 is_ok = FALSE ; 964 } else { 965 is_ok = TRUE ; 966 } 967 if (is_ok) { 968 if (!ephyrXVPrivSaveImageToPortPriv (port_priv, a_buf, image_size)) { 969 is_ok=FALSE ; 970 } else { 971 port_priv->image_id = a_id; 972 port_priv->drw_x = a_drw_x; 973 port_priv->drw_y = a_drw_y; 974 port_priv->drw_w = a_drw_w ; 975 port_priv->drw_h = a_drw_h ; 976 port_priv->src_x = a_src_x; 977 port_priv->src_y = a_src_y ; 978 port_priv->src_w = a_src_w ; 979 port_priv->src_h = a_src_h ; 980 port_priv->image_width = a_width ; 981 port_priv->image_height = a_height ; 982 } 983 } 984 if (!is_ok) { 985 if (port_priv->image_buf) { 986 free (port_priv->image_buf) ; 987 port_priv->image_buf = NULL ; 988 port_priv->image_buf_size = 0 ; 989 } 990 } 991 992 result = Success ; 993 994out: 995 EPHYR_LOG ("leave\n") ; 996 return result ; 997} 998 999static int 1000ephyrReputImage (KdScreenInfo *a_info, 1001 DrawablePtr a_drawable, 1002 short a_drw_x, 1003 short a_drw_y, 1004 RegionPtr a_clipping_region, 1005 pointer a_port_priv) 1006{ 1007 EphyrPortPriv *port_priv = a_port_priv ; 1008 int result=BadImplementation ; 1009 1010 EPHYR_RETURN_VAL_IF_FAIL (a_info->pScreen, FALSE) ; 1011 EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; 1012 1013 EPHYR_LOG ("enter\n") ; 1014 1015 if (!port_priv->image_buf_size || !port_priv->image_buf) { 1016 EPHYR_LOG_ERROR ("has null image buf in cache\n") ; 1017 goto out ; 1018 } 1019 if (!ephyrHostXVPutImage (a_info->pScreen->myNum, 1020 port_priv->port_number, 1021 port_priv->image_id, 1022 a_drw_x, a_drw_y, 1023 port_priv->drw_w, port_priv->drw_h, 1024 port_priv->src_x, port_priv->src_y, 1025 port_priv->src_w, port_priv->src_h, 1026 port_priv->image_width, port_priv->image_height, 1027 port_priv->image_buf, 1028 (EphyrHostBox*)RegionRects (a_clipping_region), 1029 RegionNumRects (a_clipping_region))) { 1030 EPHYR_LOG_ERROR ("ephyrHostXVPutImage() failed\n") ; 1031 goto out ; 1032 } 1033 1034 result = Success ; 1035 1036out: 1037 EPHYR_LOG ("leave\n") ; 1038 return result ; 1039} 1040 1041static int 1042ephyrPutVideo (KdScreenInfo *a_info, 1043 DrawablePtr a_drawable, 1044 short a_vid_x, short a_vid_y, 1045 short a_drw_x, short a_drw_y, 1046 short a_vid_w, short a_vid_h, 1047 short a_drw_w, short a_drw_h, 1048 RegionPtr a_clipping_region, 1049 pointer a_port_priv) 1050{ 1051 EphyrPortPriv *port_priv = a_port_priv ; 1052 BoxRec clipped_area, dst_box ; 1053 int result=BadImplementation ; 1054 int drw_x=0, drw_y=0, drw_w=0, drw_h=0 ; 1055 1056 EPHYR_RETURN_VAL_IF_FAIL (a_info->pScreen, BadValue) ; 1057 EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; 1058 1059 EPHYR_LOG ("enter\n") ; 1060 1061 dst_box.x1 = a_drw_x ; 1062 dst_box.x2 = a_drw_x + a_drw_w; 1063 dst_box.y1 = a_drw_y ; 1064 dst_box.y2 = a_drw_y + a_drw_h; 1065 1066 if (!DoSimpleClip (&dst_box, 1067 RegionExtents(a_clipping_region), 1068 &clipped_area)) { 1069 EPHYR_LOG_ERROR ("failed to simple clip\n") ; 1070 goto out ; 1071 } 1072 1073 drw_x = clipped_area.x1 ; 1074 drw_y = clipped_area.y1 ; 1075 drw_w = clipped_area.x2 - clipped_area.x1 ; 1076 drw_h = clipped_area.y2 - clipped_area.y1 ; 1077 1078 if (!ephyrHostXVPutVideo (a_info->pScreen->myNum, 1079 port_priv->port_number, 1080 a_vid_x, a_vid_y, a_vid_w, a_vid_h, 1081 a_drw_x, a_drw_y, a_drw_w, a_drw_h)) { 1082 EPHYR_LOG_ERROR ("ephyrHostXVPutVideo() failed\n") ; 1083 goto out ; 1084 } 1085 result = Success ; 1086 1087out: 1088 EPHYR_LOG ("leave\n") ; 1089 return result ; 1090} 1091 1092static int 1093ephyrGetVideo (KdScreenInfo *a_info, 1094 DrawablePtr a_drawable, 1095 short a_vid_x, short a_vid_y, 1096 short a_drw_x, short a_drw_y, 1097 short a_vid_w, short a_vid_h, 1098 short a_drw_w, short a_drw_h, 1099 RegionPtr a_clipping_region, 1100 pointer a_port_priv) 1101{ 1102 EphyrPortPriv *port_priv = a_port_priv ; 1103 BoxRec clipped_area, dst_box ; 1104 int result=BadImplementation ; 1105 int drw_x=0, drw_y=0, drw_w=0, drw_h=0 ; 1106 1107 EPHYR_RETURN_VAL_IF_FAIL (a_info && a_info->pScreen, BadValue) ; 1108 EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; 1109 1110 EPHYR_LOG ("enter\n") ; 1111 1112 dst_box.x1 = a_drw_x ; 1113 dst_box.x2 = a_drw_x + a_drw_w; 1114 dst_box.y1 = a_drw_y ; 1115 dst_box.y2 = a_drw_y + a_drw_h; 1116 1117 if (!DoSimpleClip (&dst_box, 1118 RegionExtents(a_clipping_region), 1119 &clipped_area)) { 1120 EPHYR_LOG_ERROR ("failed to simple clip\n") ; 1121 goto out ; 1122 } 1123 1124 drw_x = clipped_area.x1 ; 1125 drw_y = clipped_area.y1 ; 1126 drw_w = clipped_area.x2 - clipped_area.x1 ; 1127 drw_h = clipped_area.y2 - clipped_area.y1 ; 1128 1129 if (!ephyrHostXVGetVideo (a_info->pScreen->myNum, 1130 port_priv->port_number, 1131 a_vid_x, a_vid_y, a_vid_w, a_vid_h, 1132 a_drw_x, a_drw_y, a_drw_w, a_drw_h)) { 1133 EPHYR_LOG_ERROR ("ephyrHostXVGetVideo() failed\n") ; 1134 goto out ; 1135 } 1136 result = Success ; 1137 1138out: 1139 EPHYR_LOG ("leave\n") ; 1140 return result ; 1141} 1142 1143static int 1144ephyrPutStill (KdScreenInfo *a_info, 1145 DrawablePtr a_drawable, 1146 short a_vid_x, short a_vid_y, 1147 short a_drw_x, short a_drw_y, 1148 short a_vid_w, short a_vid_h, 1149 short a_drw_w, short a_drw_h, 1150 RegionPtr a_clipping_region, 1151 pointer a_port_priv) 1152{ 1153 EphyrPortPriv *port_priv = a_port_priv ; 1154 BoxRec clipped_area, dst_box ; 1155 int result=BadImplementation ; 1156 int drw_x=0, drw_y=0, drw_w=0, drw_h=0 ; 1157 1158 EPHYR_RETURN_VAL_IF_FAIL (a_info && a_info->pScreen, BadValue) ; 1159 EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; 1160 1161 EPHYR_LOG ("enter\n") ; 1162 1163 dst_box.x1 = a_drw_x ; 1164 dst_box.x2 = a_drw_x + a_drw_w; 1165 dst_box.y1 = a_drw_y ; 1166 dst_box.y2 = a_drw_y + a_drw_h; 1167 1168 if (!DoSimpleClip (&dst_box, 1169 RegionExtents(a_clipping_region), 1170 &clipped_area)) { 1171 EPHYR_LOG_ERROR ("failed to simple clip\n") ; 1172 goto out ; 1173 } 1174 1175 drw_x = clipped_area.x1 ; 1176 drw_y = clipped_area.y1 ; 1177 drw_w = clipped_area.x2 - clipped_area.x1 ; 1178 drw_h = clipped_area.y2 - clipped_area.y1 ; 1179 1180 if (!ephyrHostXVPutStill (a_info->pScreen->myNum, 1181 port_priv->port_number, 1182 a_vid_x, a_vid_y, a_vid_w, a_vid_h, 1183 a_drw_x, a_drw_y, a_drw_w, a_drw_h)) { 1184 EPHYR_LOG_ERROR ("ephyrHostXVPutStill() failed\n") ; 1185 goto out ; 1186 } 1187 result = Success ; 1188 1189out: 1190 EPHYR_LOG ("leave\n") ; 1191 return result ; 1192} 1193 1194static int 1195ephyrGetStill (KdScreenInfo *a_info, 1196 DrawablePtr a_drawable, 1197 short a_vid_x, short a_vid_y, 1198 short a_drw_x, short a_drw_y, 1199 short a_vid_w, short a_vid_h, 1200 short a_drw_w, short a_drw_h, 1201 RegionPtr a_clipping_region, 1202 pointer a_port_priv) 1203{ 1204 EphyrPortPriv *port_priv = a_port_priv ; 1205 BoxRec clipped_area, dst_box ; 1206 int result=BadImplementation ; 1207 int drw_x=0, drw_y=0, drw_w=0, drw_h=0 ; 1208 1209 EPHYR_RETURN_VAL_IF_FAIL (a_info && a_info->pScreen, BadValue) ; 1210 EPHYR_RETURN_VAL_IF_FAIL (a_drawable && port_priv, BadValue) ; 1211 1212 EPHYR_LOG ("enter\n") ; 1213 1214 dst_box.x1 = a_drw_x ; 1215 dst_box.x2 = a_drw_x + a_drw_w; 1216 dst_box.y1 = a_drw_y ; 1217 dst_box.y2 = a_drw_y + a_drw_h; 1218 1219 if (!DoSimpleClip (&dst_box, 1220 RegionExtents(a_clipping_region), 1221 &clipped_area)) { 1222 EPHYR_LOG_ERROR ("failed to simple clip\n") ; 1223 goto out ; 1224 } 1225 1226 drw_x = clipped_area.x1 ; 1227 drw_y = clipped_area.y1 ; 1228 drw_w = clipped_area.x2 - clipped_area.x1 ; 1229 drw_h = clipped_area.y2 - clipped_area.y1 ; 1230 1231 if (!ephyrHostXVGetStill (a_info->pScreen->myNum, 1232 port_priv->port_number, 1233 a_vid_x, a_vid_y, a_vid_w, a_vid_h, 1234 a_drw_x, a_drw_y, a_drw_w, a_drw_h)) { 1235 EPHYR_LOG_ERROR ("ephyrHostXVGetStill() failed\n") ; 1236 goto out ; 1237 } 1238 result = Success ; 1239 1240out: 1241 EPHYR_LOG ("leave\n") ; 1242 return result ; 1243} 1244 1245static int 1246ephyrQueryImageAttributes (KdScreenInfo *a_info, 1247 int a_id, 1248 unsigned short *a_w, 1249 unsigned short *a_h, 1250 int *a_pitches, 1251 int *a_offsets) 1252{ 1253 int image_size=0 ; 1254 1255 EPHYR_RETURN_VAL_IF_FAIL (a_w && a_h, FALSE) ; 1256 1257 EPHYR_LOG ("enter: dim (%dx%d), pitches: %p, offsets: %p\n", 1258 *a_w, *a_h, a_pitches, a_offsets) ; 1259 1260 if (!ephyrHostXVQueryImageAttributes (s_base_port_id, 1261 a_id, 1262 a_w, a_h, 1263 &image_size, 1264 a_pitches, a_offsets)) { 1265 EPHYR_LOG_ERROR ("EphyrHostXVQueryImageAttributes() failed\n") ; 1266 goto out ; 1267 } 1268 EPHYR_LOG ("image size: %d, dim (%dx%d)\n", image_size, *a_w, *a_h) ; 1269 1270out: 1271 EPHYR_LOG ("leave\n") ; 1272 return image_size ; 1273} 1274