XvMC.c revision 190694da
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 int 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 _XEatData(dpy, rep.length << 2); 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 int 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 _XEatData(dpy, rep.length << 2); 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 *priv_data = Xmalloc(rep.length << 2); 278 if(*priv_data) { 279 _XRead(dpy, (char*)(*priv_data), rep.length << 2); 280 *priv_count = rep.length; 281 } else 282 _XEatData(dpy, rep.length << 2); 283 } 284 285 UnlockDisplay (dpy); 286 SyncHandle (); 287 return Success; 288} 289 290Status _xvmc_destroy_context ( 291 Display *dpy, 292 XvMCContext *context 293) 294{ 295 XExtDisplayInfo *info = xvmc_find_display(dpy); 296 xvmcDestroyContextReq *req; 297 298 XvMCCheckExtension (dpy, info, BadImplementation); 299 300 LockDisplay (dpy); 301 XvMCGetReq (DestroyContext, req); 302 req->context_id = context->context_id; 303 UnlockDisplay (dpy); 304 SyncHandle (); 305 return Success; 306} 307 308 309/* 310 _xvmc_create_surface - 311 312 Pass the context and this function will fill out all the 313 information in the surface. 314 The server may return implementation-specific information 315 back in the priv_data. The size of that information will 316 an array of priv_count CARD32s. This data is allocated by 317 this function. If returned, the caller is responsible for 318 freeing it! Generally, such information is returned only if 319 the context was a direct context. 320 321*/ 322 323Status _xvmc_create_surface ( 324 Display *dpy, 325 XvMCContext *context, 326 XvMCSurface *surface, 327 int *priv_count, 328 CARD32 **priv_data 329) 330{ 331 XExtDisplayInfo *info = xvmc_find_display(dpy); 332 xvmcCreateSurfaceReply rep; 333 xvmcCreateSurfaceReq *req; 334 335 *priv_count = 0; 336 *priv_data = NULL; 337 338 XvMCCheckExtension (dpy, info, BadImplementation); 339 340 LockDisplay (dpy); 341 XvMCGetReq (CreateSurface, req); 342 343 surface->surface_id = XAllocID(dpy); 344 surface->context_id = context->context_id; 345 surface->surface_type_id = context->surface_type_id; 346 surface->width = context->width; 347 surface->height = context->height; 348 349 req->surface_id = surface->surface_id; 350 req->context_id = surface->context_id; 351 if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) { 352 UnlockDisplay (dpy); 353 SyncHandle (); 354 return BadImplementation; 355 } 356 357 if(rep.length) { 358 *priv_data = Xmalloc(rep.length << 2); 359 if(*priv_data) { 360 _XRead(dpy, (char*)(*priv_data), rep.length << 2); 361 *priv_count = rep.length; 362 } else 363 _XEatData(dpy, rep.length << 2); 364 } 365 366 UnlockDisplay (dpy); 367 SyncHandle (); 368 return Success; 369} 370 371Status _xvmc_destroy_surface ( 372 Display *dpy, 373 XvMCSurface *surface 374) 375{ 376 XExtDisplayInfo *info = xvmc_find_display(dpy); 377 xvmcDestroySurfaceReq *req; 378 379 XvMCCheckExtension (dpy, info, BadImplementation); 380 381 LockDisplay (dpy); 382 XvMCGetReq (DestroySurface, req); 383 req->surface_id = surface->surface_id; 384 UnlockDisplay (dpy); 385 SyncHandle (); 386 return Success; 387} 388 389/* 390 _xvmc_create_subpicture - 391 392 Pass the subpicture with the width, height and xvimage_id filled 393 out and this function will fill out everything else in the 394 subpicture as well as adjust the width and height if needed. 395 The server may return implementation-specific information 396 back in the priv_data. The size of that information will 397 an array of priv_count CARD32s. This data is allocated by 398 this function. If returned, the caller is responsible for 399 freeing it! Generally, such information is returned only if 400 the context was a direct context. 401 402*/ 403 404Status _xvmc_create_subpicture ( 405 Display *dpy, 406 XvMCContext *context, 407 XvMCSubpicture *subpicture, 408 int *priv_count, 409 CARD32 **priv_data 410) 411{ 412 XExtDisplayInfo *info = xvmc_find_display(dpy); 413 xvmcCreateSubpictureReply rep; 414 xvmcCreateSubpictureReq *req; 415 416 *priv_count = 0; 417 *priv_data = NULL; 418 419 XvMCCheckExtension (dpy, info, BadImplementation); 420 421 LockDisplay (dpy); 422 XvMCGetReq (CreateSubpicture, req); 423 424 subpicture->subpicture_id = XAllocID(dpy); 425 subpicture->context_id = context->context_id; 426 427 req->subpicture_id = subpicture->subpicture_id; 428 req->context_id = subpicture->context_id; 429 req->xvimage_id = subpicture->xvimage_id; 430 req->width = subpicture->width; 431 req->height = subpicture->height; 432 if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) { 433 UnlockDisplay (dpy); 434 SyncHandle (); 435 return BadImplementation; 436 } 437 438 subpicture->width = rep.width_actual; 439 subpicture->height = rep.height_actual; 440 subpicture->num_palette_entries = rep.num_palette_entries; 441 subpicture->entry_bytes = rep.entry_bytes; 442 subpicture->component_order[0] = rep.component_order[0]; 443 subpicture->component_order[1] = rep.component_order[1]; 444 subpicture->component_order[2] = rep.component_order[2]; 445 subpicture->component_order[3] = rep.component_order[3]; 446 447 if(rep.length) { 448 *priv_data = Xmalloc(rep.length << 2); 449 if(*priv_data) { 450 _XRead(dpy, (char*)(*priv_data), rep.length << 2); 451 *priv_count = rep.length; 452 } else 453 _XEatData(dpy, rep.length << 2); 454 } 455 456 UnlockDisplay (dpy); 457 SyncHandle (); 458 return Success; 459} 460 461Status _xvmc_destroy_subpicture( 462 Display *dpy, 463 XvMCSubpicture *subpicture 464) 465{ 466 XExtDisplayInfo *info = xvmc_find_display(dpy); 467 xvmcDestroySubpictureReq *req; 468 469 XvMCCheckExtension (dpy, info, BadImplementation); 470 471 LockDisplay (dpy); 472 XvMCGetReq (DestroySubpicture, req); 473 req->subpicture_id = subpicture->subpicture_id; 474 UnlockDisplay (dpy); 475 SyncHandle (); 476 return Success; 477} 478 479Status XvMCGetDRInfo(Display *dpy, XvPortID port, 480 char **name, char **busID, 481 int *major, int *minor, 482 int *patchLevel, 483 int *isLocal) 484{ 485 XExtDisplayInfo *info = xvmc_find_display(dpy); 486 xvmcGetDRInfoReply rep; 487 xvmcGetDRInfoReq *req; 488 CARD32 magic; 489 490#ifdef HAVE_SHMAT 491 volatile CARD32 *shMem; 492 struct timezone here; 493 struct timeval now; 494 here.tz_minuteswest = 0; 495 here.tz_dsttime = 0; 496#endif 497 498 *name = NULL; 499 *busID = NULL; 500 501 XvMCCheckExtension (dpy, info, BadImplementation); 502 503 LockDisplay (dpy); 504 XvMCGetReq (GetDRInfo, req); 505 506 req->port = port; 507 magic = 0; 508 req->magic = 0; 509#ifdef HAVE_SHMAT 510 req->shmKey = shmget(IPC_PRIVATE, 1024, IPC_CREAT | 0600); 511 512 /* 513 * We fill a shared memory page with a repetitive pattern. If the 514 * X server can read this pattern, we probably have a local connection. 515 * Note that we can trigger the remote X server to read any shared 516 * page on the remote machine, so we shouldn't be able to guess and verify 517 * any complicated data on those pages. Thats the explanation of this 518 * otherwise stupid-looking pattern algorithm. 519 */ 520 521 if (req->shmKey >= 0) { 522 shMem = (CARD32 *) shmat(req->shmKey, NULL, 0); 523 shmctl( req->shmKey, IPC_RMID, NULL); 524 if ( shMem ) { 525 526 register volatile CARD32 *shMemC = shMem; 527 register int i; 528 529 gettimeofday( &now, &here); 530 magic = now.tv_usec & 0x000FFFFF; 531 req->magic = magic; 532 i = 1024 / sizeof(CARD32); 533 while(i--) { 534 *shMemC++ = magic; 535 magic = ~magic; 536 } 537 } else { 538 req->shmKey = -1; 539 } 540 } 541#else 542 req->shmKey = 0; 543#endif 544 if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) { 545 UnlockDisplay (dpy); 546 SyncHandle (); 547#ifdef HAVE_SHMAT 548 if ( req->shmKey >= 0) { 549 shmdt( (const void *) shMem ); 550 } 551#endif 552 return -1; 553 } 554#ifdef HAVE_SHMAT 555 shmdt( (const void *) shMem ); 556#endif 557 558 if (rep.length > 0) { 559 unsigned long realSize = 0; 560 char *tmpBuf = NULL; 561 562 if (rep.length < (INT_MAX >> 2)) { 563 realSize = rep.length << 2; 564 if (realSize >= (rep.nameLen + rep.busIDLen)) { 565 tmpBuf = Xmalloc(realSize); 566 *name = Xmalloc(rep.nameLen); 567 *busID = Xmalloc(rep.busIDLen); 568 } 569 } 570 571 if (*name && *busID && tmpBuf) { 572 _XRead(dpy, tmpBuf, realSize); 573 strncpy(*name,tmpBuf,rep.nameLen); 574 name[rep.nameLen - 1] = '\0'; 575 strncpy(*busID,tmpBuf+rep.nameLen,rep.busIDLen); 576 busID[rep.busIDLen - 1] = '\0'; 577 XFree(tmpBuf); 578 } else { 579 XFree(*name); 580 *name = NULL; 581 XFree(*busID); 582 *name = NULL; 583 XFree(tmpBuf); 584 585 _XEatData(dpy, realSize); 586 UnlockDisplay (dpy); 587 SyncHandle (); 588 return -1; 589 590 } 591 } 592 593 UnlockDisplay (dpy); 594 SyncHandle (); 595 *major = rep.major; 596 *minor = rep.minor; 597 *patchLevel = rep.patchLevel; 598 *isLocal = (req->shmKey > 0) ? rep.isLocal : 1; 599 return (rep.length > 0) ? Success : BadImplementation; 600} 601 602