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