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