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