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