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