XvMC.c revision f1c62215
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	   _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            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	   _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    volatile CARD32 *shMem;
495    struct timezone here;
496    struct timeval now;
497    here.tz_minuteswest = 0;
498    here.tz_dsttime = 0;
499#endif
500
501    *name = NULL;
502    *busID = NULL;
503
504    XvMCCheckExtension (dpy, info, BadImplementation);
505
506    LockDisplay (dpy);
507    XvMCGetReq (GetDRInfo, req);
508
509    req->port = port;
510    magic = 0;
511    req->magic = 0;
512#ifdef HAVE_SHMAT
513    req->shmKey = shmget(IPC_PRIVATE, 1024, IPC_CREAT | 0600);
514
515    /*
516     * We fill a shared memory page with a repetitive pattern. If the
517     * X server can read this pattern, we probably have a local connection.
518     * Note that we can trigger the remote X server to read any shared
519     * page on the remote machine, so we shouldn't be able to guess and verify
520     * any complicated data on those pages. Thats the explanation of this
521     * otherwise stupid-looking pattern algorithm.
522     */
523
524    if (req->shmKey >= 0) {
525	shMem = (CARD32 *) shmat(req->shmKey, NULL, 0);
526	shmctl( req->shmKey, IPC_RMID, NULL);
527	if ( shMem ) {
528
529	    register volatile CARD32 *shMemC = shMem;
530	    register int i;
531
532	    gettimeofday( &now, &here);
533	    magic = now.tv_usec & 0x000FFFFF;
534	    req->magic = magic;
535	    i = 1024 / sizeof(CARD32);
536	    while(i--) {
537	        *shMemC++ = magic;
538	        magic = ~magic;
539	    }
540	} else {
541	    req->shmKey = -1;
542	}
543    }
544#else
545    req->shmKey = 0;
546#endif
547    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
548        UnlockDisplay (dpy);
549        SyncHandle ();
550#ifdef HAVE_SHMAT
551	if ( req->shmKey >= 0) {
552	    shmdt( (const void *) shMem );
553	}
554#endif
555        return -1;
556    }
557#ifdef HAVE_SHMAT
558    shmdt( (const void *) shMem );
559#endif
560
561    if (rep.length > 0) {
562	unsigned long realSize = 0;
563	char *tmpBuf = NULL;
564
565	if ((rep.length < (INT_MAX >> 2)) &&
566	    /* protect against overflow in strncpy below */
567	    (rep.nameLen + rep.busIDLen > rep.nameLen)) {
568	    realSize = rep.length << 2;
569	    if (realSize >= (rep.nameLen + rep.busIDLen)) {
570		tmpBuf = Xmalloc(realSize);
571		*name = Xmalloc(rep.nameLen);
572		*busID = Xmalloc(rep.busIDLen);
573	    }
574	}
575
576	if (*name && *busID && tmpBuf) {
577	    _XRead(dpy, tmpBuf, realSize);
578	    strncpy(*name,tmpBuf,rep.nameLen);
579	    (*name)[rep.nameLen == 0 ? 0 : rep.nameLen - 1] = '\0';
580	    strncpy(*busID,tmpBuf+rep.nameLen,rep.busIDLen);
581	    (*busID)[rep.busIDLen == 0 ? 0 : rep.busIDLen - 1] = '\0';
582	    XFree(tmpBuf);
583	} else {
584	    XFree(*name);
585	    *name = NULL;
586	    XFree(*busID);
587	    *busID = NULL;
588	    XFree(tmpBuf);
589
590	    _XEatDataWords(dpy, rep.length);
591	    UnlockDisplay (dpy);
592	    SyncHandle ();
593	    return -1;
594
595	}
596    }
597
598    UnlockDisplay (dpy);
599    SyncHandle ();
600    *major = rep.major;
601    *minor = rep.minor;
602    *patchLevel = rep.patchLevel;
603    *isLocal = (req->shmKey > 0) ? rep.isLocal : 1;
604    return (rep.length > 0) ? Success : BadImplementation;
605}
606
607