1#ifdef HAVE_CONFIG_H 2#include <config.h> 3#endif 4#include <stdio.h> 5#include "XvMClibint.h" 6#ifdef HAVE_SHMAT 7#ifndef Lynx 8#include <sys/ipc.h> 9#include <sys/shm.h> 10#else 11#include <ipc.h> 12#include <shm.h> 13#endif /* Lynx */ 14#endif /* HAVE_SHMAT */ 15#include <unistd.h> 16#include <sys/time.h> 17#include <X11/extensions/Xext.h> 18#include <X11/extensions/extutil.h> 19#include <limits.h> 20 21static XExtensionInfo _xvmc_info_data; 22static XExtensionInfo *xvmc_info = &_xvmc_info_data; 23static const char *xvmc_extension_name = XvMCName; 24 25static const char *xvmc_error_list[] = { 26 "BadContext", 27 "BadSurface", 28 "BadSubpicture" 29}; 30 31static XEXT_GENERATE_CLOSE_DISPLAY(xvmc_close_display, xvmc_info) 32static XEXT_GENERATE_ERROR_STRING(xvmc_error_string, xvmc_extension_name, 33 XvMCNumErrors, xvmc_error_list) 34 35static XExtensionHooks xvmc_extension_hooks = { 36 NULL, /* create_gc */ 37 NULL, /* copy_gc */ 38 NULL, /* flush_gc */ 39 NULL, /* free_gc */ 40 NULL, /* create_font */ 41 NULL, /* free_font */ 42 xvmc_close_display, /* close_display */ 43 NULL, /* wire_to_event */ 44 NULL, /* event_to_wire */ 45 NULL, /* error */ 46 xvmc_error_string /* error_string */ 47}; 48 49static XEXT_GENERATE_FIND_DISPLAY(xvmc_find_display, xvmc_info, 50 xvmc_extension_name, 51 &xvmc_extension_hooks, 52 XvMCNumEvents, NULL) 53 54Bool 55XvMCQueryExtension(Display *dpy, int *event_basep, int *error_basep) 56{ 57 XExtDisplayInfo *info = xvmc_find_display(dpy); 58 59 if (XextHasExtension(info)) { 60 *event_basep = info->codes->first_event; 61 *error_basep = info->codes->first_error; 62 return True; 63 } 64 else { 65 return False; 66 } 67} 68 69Status 70XvMCQueryVersion(Display *dpy, int *major, int *minor) 71{ 72 XExtDisplayInfo *info = xvmc_find_display(dpy); 73 xvmcQueryVersionReply rep; 74 xvmcQueryVersionReq *req; 75 76 XvMCCheckExtension(dpy, info, BadImplementation); 77 78 LockDisplay(dpy); 79 XvMCGetReq(QueryVersion, req); 80 if (!_XReply(dpy, (xReply *) &rep, 0, xTrue)) { 81 UnlockDisplay(dpy); 82 SyncHandle(); 83 return BadImplementation; 84 } 85 *major = (int) rep.major; 86 *minor = (int) rep.minor; 87 UnlockDisplay(dpy); 88 SyncHandle(); 89 return Success; 90} 91 92XvMCSurfaceInfo * 93XvMCListSurfaceTypes(Display *dpy, XvPortID port, int *num) 94{ 95 XExtDisplayInfo *info = xvmc_find_display(dpy); 96 xvmcListSurfaceTypesReply rep; 97 xvmcListSurfaceTypesReq *req; 98 XvMCSurfaceInfo *surface_info = NULL; 99 100 *num = 0; 101 102 XvMCCheckExtension(dpy, info, NULL); 103 104 LockDisplay(dpy); 105 XvMCGetReq(ListSurfaceTypes, req); 106 req->port = (CARD32) port; 107 if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) { 108 UnlockDisplay(dpy); 109 SyncHandle(); 110 return NULL; 111 } 112 113 if (rep.num > 0) { 114 if (rep.num < (INT_MAX / sizeof(XvMCSurfaceInfo))) 115 surface_info = Xmalloc(rep.num * sizeof(XvMCSurfaceInfo)); 116 117 if (surface_info) { 118 *num = (int) rep.num; 119 120 for (CARD32 i = 0; i < rep.num; i++) { 121 xvmcSurfaceInfo sinfo; 122 123 _XRead(dpy, (char *) &sinfo, sizeof(xvmcSurfaceInfo)); 124 surface_info[i].surface_type_id = (int) sinfo.surface_type_id; 125 surface_info[i].chroma_format = sinfo.chroma_format; 126 surface_info[i].max_width = sinfo.max_width; 127 surface_info[i].max_height = sinfo.max_height; 128 surface_info[i].subpicture_max_width = 129 sinfo.subpicture_max_width; 130 surface_info[i].subpicture_max_height = 131 sinfo.subpicture_max_height; 132 surface_info[i].mc_type = (int) sinfo.mc_type; 133 surface_info[i].flags = (int) sinfo.flags; 134 } 135 } 136 else 137 _XEatDataWords(dpy, rep.length); 138 } 139 140 UnlockDisplay(dpy); 141 SyncHandle(); 142 return surface_info; 143} 144 145XvImageFormatValues * 146XvMCListSubpictureTypes(Display *dpy, 147 XvPortID port, 148 int surface_type_id, 149 int *count_return) 150{ 151 XExtDisplayInfo *info = xvmc_find_display(dpy); 152 xvmcListSubpictureTypesReply rep; 153 xvmcListSubpictureTypesReq *req; 154 XvImageFormatValues *ret = NULL; 155 156 *count_return = 0; 157 158 XvMCCheckExtension(dpy, info, NULL); 159 160 LockDisplay(dpy); 161 XvMCGetReq(ListSubpictureTypes, req); 162 req->port = (CARD32) port; 163 req->surface_type_id = (CARD32) surface_type_id; 164 if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) { 165 UnlockDisplay(dpy); 166 SyncHandle(); 167 return NULL; 168 } 169 170 if (rep.num > 0) { 171 if (rep.num < (INT_MAX / sizeof(XvImageFormatValues))) 172 ret = Xmalloc(rep.num * sizeof(XvImageFormatValues)); 173 174 if (ret) { 175 *count_return = (int) rep.num; 176 177 for (CARD32 i = 0; i < rep.num; i++) { 178 xvImageFormatInfo Info; 179 180 _XRead(dpy, (char *) (&Info), sz_xvImageFormatInfo); 181 ret[i].id = (int) Info.id; 182 ret[i].type = Info.type; 183 ret[i].byte_order = Info.byte_order; 184 memcpy(&(ret[i].guid[0]), &(Info.guid[0]), 16); 185 ret[i].bits_per_pixel = Info.bpp; 186 ret[i].format = Info.format; 187 ret[i].num_planes = Info.num_planes; 188 ret[i].depth = Info.depth; 189 ret[i].red_mask = Info.red_mask; 190 ret[i].green_mask = Info.green_mask; 191 ret[i].blue_mask = Info.blue_mask; 192 ret[i].y_sample_bits = Info.y_sample_bits; 193 ret[i].u_sample_bits = Info.u_sample_bits; 194 ret[i].v_sample_bits = Info.v_sample_bits; 195 ret[i].horz_y_period = Info.horz_y_period; 196 ret[i].horz_u_period = Info.horz_u_period; 197 ret[i].horz_v_period = Info.horz_v_period; 198 ret[i].vert_y_period = Info.vert_y_period; 199 ret[i].vert_u_period = Info.vert_u_period; 200 ret[i].vert_v_period = Info.vert_v_period; 201 memcpy(&(ret[i].component_order[0]), &(Info.comp_order[0]), 32); 202 ret[i].scanline_order = Info.scanline_order; 203 } 204 } 205 else 206 _XEatDataWords(dpy, rep.length); 207 } 208 209 UnlockDisplay(dpy); 210 SyncHandle(); 211 return ret; 212} 213 214/****************************************************************** 215 These are intended as a protocol interface to be used by direct 216 rendering libraries. They are not intended to be client viewable 217 functions. These will stay in place until we have a mechanism in 218 place similar to that of OpenGL with an libXvMCcore library. 219*******************************************************************/ 220 221/* 222 _xvmc_create_context - 223 224 Pass in the context with the surface_type_id, width, height, 225 port and flags filled out. This function will fill out the 226 context_id and update the width, height and flags field. 227 The server may return implementation-specific information 228 back in the priv_data. The size of that information will 229 an array of priv_count CARD32s. This data is allocated by 230 this function. If returned, the caller is responsible for 231 freeing it! Generally, such information is only returned if 232 an XVMC_DIRECT context was specified. 233*/ 234 235Status 236_xvmc_create_context(Display *dpy, 237 XvMCContext *context, 238 int *priv_count, 239 CARD32 **priv_data) 240{ 241 XExtDisplayInfo *info = xvmc_find_display(dpy); 242 xvmcCreateContextReply rep; 243 xvmcCreateContextReq *req; 244 245 *priv_count = 0; 246 *priv_data = NULL; 247 248 XvMCCheckExtension(dpy, info, BadImplementation); 249 250 LockDisplay(dpy); 251 XvMCGetReq(CreateContext, req); 252 context->context_id = XAllocID(dpy); 253 req->context_id = (CARD32) context->context_id; 254 req->port = (CARD32) context->port; 255 req->surface_type_id = (CARD32) context->surface_type_id; 256 req->width = context->width; 257 req->height = context->height; 258 req->flags = (CARD32) context->flags; 259 if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) { 260 UnlockDisplay(dpy); 261 SyncHandle(); 262 return BadImplementation; 263 } 264 context->width = rep.width_actual; 265 context->height = rep.height_actual; 266 context->flags = (int) rep.flags_return; 267 268 if (rep.length) { 269 if (rep.length < (INT_MAX >> 2)) 270 *priv_data = Xmalloc(rep.length << 2); 271 if (*priv_data) { 272 _XRead(dpy, (char *) (*priv_data), rep.length << 2); 273 *priv_count = (int) rep.length; 274 } 275 else 276 _XEatDataWords(dpy, rep.length); 277 } 278 279 UnlockDisplay(dpy); 280 SyncHandle(); 281 return Success; 282} 283 284Status 285_xvmc_destroy_context(Display *dpy, XvMCContext *context) 286{ 287 XExtDisplayInfo *info = xvmc_find_display(dpy); 288 xvmcDestroyContextReq *req; 289 290 XvMCCheckExtension(dpy, info, BadImplementation); 291 292 LockDisplay(dpy); 293 XvMCGetReq(DestroyContext, req); 294 req->context_id = (CARD32) context->context_id; 295 UnlockDisplay(dpy); 296 SyncHandle(); 297 return Success; 298} 299 300/* 301 _xvmc_create_surface - 302 303 Pass the context and this function will fill out all the 304 information in the surface. 305 The server may return implementation-specific information 306 back in the priv_data. The size of that information will 307 an array of priv_count CARD32s. This data is allocated by 308 this function. If returned, the caller is responsible for 309 freeing it! Generally, such information is returned only if 310 the context was a direct context. 311 312*/ 313 314Status 315_xvmc_create_surface(Display *dpy, 316 XvMCContext *context, 317 XvMCSurface *surface, 318 int *priv_count, 319 CARD32 **priv_data) 320{ 321 XExtDisplayInfo *info = xvmc_find_display(dpy); 322 xvmcCreateSurfaceReply rep; 323 xvmcCreateSurfaceReq *req; 324 325 *priv_count = 0; 326 *priv_data = NULL; 327 328 XvMCCheckExtension(dpy, info, BadImplementation); 329 330 LockDisplay(dpy); 331 XvMCGetReq(CreateSurface, req); 332 333 surface->surface_id = XAllocID(dpy); 334 surface->context_id = context->context_id; 335 surface->surface_type_id = context->surface_type_id; 336 surface->width = context->width; 337 surface->height = context->height; 338 339 req->surface_id = (CARD32) surface->surface_id; 340 req->context_id = (CARD32) surface->context_id; 341 if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) { 342 UnlockDisplay(dpy); 343 SyncHandle(); 344 return BadImplementation; 345 } 346 347 if (rep.length) { 348 if (rep.length < (INT_MAX >> 2)) 349 *priv_data = Xmalloc(rep.length << 2); 350 if (*priv_data) { 351 _XRead(dpy, (char *) (*priv_data), rep.length << 2); 352 *priv_count = (int) rep.length; 353 } 354 else 355 _XEatDataWords(dpy, rep.length); 356 } 357 358 UnlockDisplay(dpy); 359 SyncHandle(); 360 return Success; 361} 362 363Status 364_xvmc_destroy_surface(Display *dpy, XvMCSurface *surface) 365{ 366 XExtDisplayInfo *info = xvmc_find_display(dpy); 367 xvmcDestroySurfaceReq *req; 368 369 XvMCCheckExtension(dpy, info, BadImplementation); 370 371 LockDisplay(dpy); 372 XvMCGetReq(DestroySurface, req); 373 req->surface_id = (CARD32) surface->surface_id; 374 UnlockDisplay(dpy); 375 SyncHandle(); 376 return Success; 377} 378 379/* 380 _xvmc_create_subpicture - 381 382 Pass the subpicture with the width, height and xvimage_id filled 383 out and this function will fill out everything else in the 384 subpicture as well as adjust the width and height if needed. 385 The server may return implementation-specific information 386 back in the priv_data. The size of that information will 387 an array of priv_count CARD32s. This data is allocated by 388 this function. If returned, the caller is responsible for 389 freeing it! Generally, such information is returned only if 390 the context was a direct context. 391 392*/ 393 394Status 395_xvmc_create_subpicture(Display *dpy, 396 XvMCContext *context, 397 XvMCSubpicture *subpicture, 398 int *priv_count, 399 CARD32 **priv_data) 400{ 401 XExtDisplayInfo *info = xvmc_find_display(dpy); 402 xvmcCreateSubpictureReply rep; 403 xvmcCreateSubpictureReq *req; 404 405 *priv_count = 0; 406 *priv_data = NULL; 407 408 XvMCCheckExtension(dpy, info, BadImplementation); 409 410 LockDisplay(dpy); 411 XvMCGetReq(CreateSubpicture, req); 412 413 subpicture->subpicture_id = XAllocID(dpy); 414 subpicture->context_id = context->context_id; 415 416 req->subpicture_id = (CARD32) subpicture->subpicture_id; 417 req->context_id = (CARD32) subpicture->context_id; 418 req->xvimage_id = (CARD32) subpicture->xvimage_id; 419 req->width = subpicture->width; 420 req->height = subpicture->height; 421 if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) { 422 UnlockDisplay(dpy); 423 SyncHandle(); 424 return BadImplementation; 425 } 426 427 subpicture->width = rep.width_actual; 428 subpicture->height = rep.height_actual; 429 subpicture->num_palette_entries = rep.num_palette_entries; 430 subpicture->entry_bytes = rep.entry_bytes; 431 subpicture->component_order[0] = (char) rep.component_order[0]; 432 subpicture->component_order[1] = (char) rep.component_order[1]; 433 subpicture->component_order[2] = (char) rep.component_order[2]; 434 subpicture->component_order[3] = (char) rep.component_order[3]; 435 436 if (rep.length) { 437 if (rep.length < (INT_MAX >> 2)) 438 *priv_data = Xmalloc(rep.length << 2); 439 if (*priv_data) { 440 _XRead(dpy, (char *) (*priv_data), rep.length << 2); 441 *priv_count = (int) rep.length; 442 } 443 else 444 _XEatDataWords(dpy, rep.length); 445 } 446 447 UnlockDisplay(dpy); 448 SyncHandle(); 449 return Success; 450} 451 452Status 453_xvmc_destroy_subpicture(Display *dpy, XvMCSubpicture *subpicture) 454{ 455 XExtDisplayInfo *info = xvmc_find_display(dpy); 456 xvmcDestroySubpictureReq *req; 457 458 XvMCCheckExtension(dpy, info, BadImplementation); 459 460 LockDisplay(dpy); 461 XvMCGetReq(DestroySubpicture, req); 462 req->subpicture_id = (CARD32) subpicture->subpicture_id; 463 UnlockDisplay(dpy); 464 SyncHandle(); 465 return Success; 466} 467 468Status 469XvMCGetDRInfo(Display *dpy, XvPortID port, 470 char **name, char **busID, 471 int *major, int *minor, 472 int *patchLevel, 473 int *isLocal) 474{ 475 XExtDisplayInfo *info = xvmc_find_display(dpy); 476 xvmcGetDRInfoReply rep; 477 xvmcGetDRInfoReq *req; 478 479#ifdef HAVE_SHMAT 480 int shmKey; 481 volatile CARD32 *shMem; 482#endif 483 484 *name = NULL; 485 *busID = NULL; 486 487 XvMCCheckExtension(dpy, info, BadImplementation); 488 489 LockDisplay(dpy); 490 XvMCGetReq(GetDRInfo, req); 491 492 req->port = (CARD32) port; 493 req->magic = 0; 494#ifdef HAVE_SHMAT 495 shmKey = shmget(IPC_PRIVATE, 1024, IPC_CREAT | 0600); 496 req->shmKey = (CARD32) shmKey; 497 498 /* 499 * We fill a shared memory page with a repetitive pattern. If the 500 * X server can read this pattern, we probably have a local connection. 501 * Note that we can trigger the remote X server to read any shared 502 * page on the remote machine, so we shouldn't be able to guess and verify 503 * any complicated data on those pages. That's the explanation of this 504 * otherwise stupid-looking pattern algorithm. 505 */ 506 507 if (shmKey >= 0) { 508 shMem = (CARD32 *) shmat(shmKey, NULL, 0); 509 shmctl(shmKey, IPC_RMID, NULL); 510 if (shMem != (void *) -1) { 511 512 register volatile CARD32 *shMemC = shMem; 513 register int i; 514 CARD32 magic; 515 struct timezone here = {0, 0}; 516 struct timeval now; 517 518 gettimeofday(&now, &here); 519 magic = now.tv_usec & 0x000FFFFF; 520 req->magic = magic; 521 i = 1024 / sizeof(CARD32); 522 while (i--) { 523 *shMemC++ = magic; 524 magic = ~magic; 525 } 526 } 527 else { 528 req->shmKey = (CARD32) -1; 529 shmKey = -1; 530 } 531 } 532#else 533 req->shmKey = 0; 534#endif 535 if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) { 536 UnlockDisplay(dpy); 537 SyncHandle(); 538#ifdef HAVE_SHMAT 539 if (shmKey >= 0) { 540 shmdt((const void *) shMem); 541 } 542#endif 543 return -1; 544 } 545#ifdef HAVE_SHMAT 546 if (shmKey >= 0) { 547 shmdt((const void *) shMem); 548 } 549#endif 550 551 if (rep.length > 0) { 552 unsigned long realSize = 0; 553 char *tmpBuf = NULL; 554 555 if ((rep.length < (INT_MAX >> 2)) && 556 /* protect against overflow in strncpy below */ 557 (rep.nameLen + rep.busIDLen > rep.nameLen)) { 558 realSize = rep.length << 2; 559 if (realSize >= (rep.nameLen + rep.busIDLen)) { 560 tmpBuf = Xmalloc(realSize); 561 *name = Xmalloc(rep.nameLen); 562 *busID = Xmalloc(rep.busIDLen); 563 } 564 } 565 566 if (*name && *busID && tmpBuf) { 567 _XRead(dpy, tmpBuf, (long) realSize); 568 strncpy(*name, tmpBuf, rep.nameLen); 569 (*name)[rep.nameLen == 0 ? 0 : rep.nameLen - 1] = '\0'; 570 strncpy(*busID, tmpBuf + rep.nameLen, rep.busIDLen); 571 (*busID)[rep.busIDLen == 0 ? 0 : rep.busIDLen - 1] = '\0'; 572 XFree(tmpBuf); 573 } 574 else { 575 XFree(*name); 576 *name = NULL; 577 XFree(*busID); 578 *busID = NULL; 579 XFree(tmpBuf); 580 581 _XEatDataWords(dpy, rep.length); 582 UnlockDisplay(dpy); 583 SyncHandle(); 584 return -1; 585 586 } 587 } 588 589 UnlockDisplay(dpy); 590 SyncHandle(); 591 *major = (int) rep.major; 592 *minor = (int) rep.minor; 593 *patchLevel = (int) rep.patchLevel; 594#ifdef HAVE_SHMAT 595 if (shmKey >= 0) 596 *isLocal = (int) rep.isLocal; 597 else 598#endif 599 *isLocal = 1; 600 return (rep.length > 0) ? Success : BadImplementation; 601} 602