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