XvMC.c revision 190694da
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	   _XEatData(dpy, rep.length << 2);
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	   _XEatData(dpy, rep.length << 2);
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	*priv_data = Xmalloc(rep.length << 2);
278	if(*priv_data) {
279            _XRead(dpy, (char*)(*priv_data), rep.length << 2);
280	    *priv_count = rep.length;
281	} else
282	    _XEatData(dpy, rep.length << 2);
283    }
284
285    UnlockDisplay (dpy);
286    SyncHandle ();
287    return Success;
288}
289
290Status _xvmc_destroy_context (
291    Display *dpy,
292    XvMCContext *context
293)
294{
295    XExtDisplayInfo *info = xvmc_find_display(dpy);
296    xvmcDestroyContextReq  *req;
297
298    XvMCCheckExtension (dpy, info, BadImplementation);
299
300    LockDisplay (dpy);
301    XvMCGetReq (DestroyContext, req);
302    req->context_id = context->context_id;
303    UnlockDisplay (dpy);
304    SyncHandle ();
305    return Success;
306}
307
308
309/*
310   _xvmc_create_surface -
311
312   Pass the context and this function will fill out all the
313   information in the surface.
314   The server may return implementation-specific information
315   back in the priv_data.  The size of that information will
316   an array of priv_count CARD32s.  This data is allocated by
317   this function.  If returned, the caller is responsible for
318   freeing it!  Generally, such information is returned only if
319   the context was a direct context.
320
321*/
322
323Status _xvmc_create_surface (
324    Display *dpy,
325    XvMCContext *context,
326    XvMCSurface *surface,
327    int *priv_count,
328    CARD32 **priv_data
329)
330{
331    XExtDisplayInfo *info = xvmc_find_display(dpy);
332    xvmcCreateSurfaceReply rep;
333    xvmcCreateSurfaceReq  *req;
334
335    *priv_count = 0;
336    *priv_data = NULL;
337
338    XvMCCheckExtension (dpy, info, BadImplementation);
339
340    LockDisplay (dpy);
341    XvMCGetReq (CreateSurface, req);
342
343    surface->surface_id = XAllocID(dpy);
344    surface->context_id = context->context_id;
345    surface->surface_type_id = context->surface_type_id;
346    surface->width = context->width;
347    surface->height = context->height;
348
349    req->surface_id = surface->surface_id;
350    req->context_id = surface->context_id;
351    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
352        UnlockDisplay (dpy);
353        SyncHandle ();
354        return BadImplementation;
355    }
356
357    if(rep.length) {
358        *priv_data = Xmalloc(rep.length << 2);
359        if(*priv_data) {
360            _XRead(dpy, (char*)(*priv_data), rep.length << 2);
361            *priv_count = rep.length;
362        } else
363            _XEatData(dpy, rep.length << 2);
364    }
365
366    UnlockDisplay (dpy);
367    SyncHandle ();
368    return Success;
369}
370
371Status _xvmc_destroy_surface (
372    Display *dpy,
373    XvMCSurface *surface
374)
375{
376    XExtDisplayInfo *info = xvmc_find_display(dpy);
377    xvmcDestroySurfaceReq  *req;
378
379    XvMCCheckExtension (dpy, info, BadImplementation);
380
381    LockDisplay (dpy);
382    XvMCGetReq (DestroySurface, req);
383    req->surface_id = surface->surface_id;
384    UnlockDisplay (dpy);
385    SyncHandle ();
386    return Success;
387}
388
389/*
390   _xvmc_create_subpicture -
391
392   Pass the subpicture with the width, height and xvimage_id filled
393   out and this function will fill out everything else in the
394   subpicture as well as adjust the width and height if needed.
395   The server may return implementation-specific information
396   back in the priv_data.  The size of that information will
397   an array of priv_count CARD32s.  This data is allocated by
398   this function.  If returned, the caller is responsible for
399   freeing it!  Generally, such information is returned only if
400   the context was a direct context.
401
402*/
403
404Status _xvmc_create_subpicture (
405    Display *dpy,
406    XvMCContext *context,
407    XvMCSubpicture *subpicture,
408    int *priv_count,
409    CARD32 **priv_data
410)
411{
412    XExtDisplayInfo *info = xvmc_find_display(dpy);
413    xvmcCreateSubpictureReply rep;
414    xvmcCreateSubpictureReq  *req;
415
416    *priv_count = 0;
417    *priv_data = NULL;
418
419    XvMCCheckExtension (dpy, info, BadImplementation);
420
421    LockDisplay (dpy);
422    XvMCGetReq (CreateSubpicture, req);
423
424    subpicture->subpicture_id = XAllocID(dpy);
425    subpicture->context_id = context->context_id;
426
427    req->subpicture_id = subpicture->subpicture_id;
428    req->context_id = subpicture->context_id;
429    req->xvimage_id = subpicture->xvimage_id;
430    req->width = subpicture->width;
431    req->height = subpicture->height;
432    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
433        UnlockDisplay (dpy);
434        SyncHandle ();
435        return BadImplementation;
436    }
437
438    subpicture->width = rep.width_actual;
439    subpicture->height = rep.height_actual;
440    subpicture->num_palette_entries = rep.num_palette_entries;
441    subpicture->entry_bytes = rep.entry_bytes;
442    subpicture->component_order[0] = rep.component_order[0];
443    subpicture->component_order[1] = rep.component_order[1];
444    subpicture->component_order[2] = rep.component_order[2];
445    subpicture->component_order[3] = rep.component_order[3];
446
447    if(rep.length) {
448        *priv_data = Xmalloc(rep.length << 2);
449        if(*priv_data) {
450            _XRead(dpy, (char*)(*priv_data), rep.length << 2);
451            *priv_count = rep.length;
452        } else
453            _XEatData(dpy, rep.length << 2);
454    }
455
456    UnlockDisplay (dpy);
457    SyncHandle ();
458    return Success;
459}
460
461Status _xvmc_destroy_subpicture(
462    Display *dpy,
463    XvMCSubpicture *subpicture
464)
465{
466    XExtDisplayInfo *info = xvmc_find_display(dpy);
467    xvmcDestroySubpictureReq  *req;
468
469    XvMCCheckExtension (dpy, info, BadImplementation);
470
471    LockDisplay (dpy);
472    XvMCGetReq (DestroySubpicture, req);
473    req->subpicture_id = subpicture->subpicture_id;
474    UnlockDisplay (dpy);
475    SyncHandle ();
476    return Success;
477}
478
479Status XvMCGetDRInfo(Display *dpy, XvPortID port,
480		     char **name, char **busID,
481		     int *major, int *minor,
482		     int *patchLevel,
483		     int *isLocal)
484{
485    XExtDisplayInfo *info = xvmc_find_display(dpy);
486    xvmcGetDRInfoReply rep;
487    xvmcGetDRInfoReq  *req;
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    *name = NULL;
499    *busID = NULL;
500
501    XvMCCheckExtension (dpy, info, BadImplementation);
502
503    LockDisplay (dpy);
504    XvMCGetReq (GetDRInfo, req);
505
506    req->port = port;
507    magic = 0;
508    req->magic = 0;
509#ifdef HAVE_SHMAT
510    req->shmKey = shmget(IPC_PRIVATE, 1024, IPC_CREAT | 0600);
511
512    /*
513     * We fill a shared memory page with a repetitive pattern. If the
514     * X server can read this pattern, we probably have a local connection.
515     * Note that we can trigger the remote X server to read any shared
516     * page on the remote machine, so we shouldn't be able to guess and verify
517     * any complicated data on those pages. Thats the explanation of this
518     * otherwise stupid-looking pattern algorithm.
519     */
520
521    if (req->shmKey >= 0) {
522	shMem = (CARD32 *) shmat(req->shmKey, NULL, 0);
523	shmctl( req->shmKey, IPC_RMID, NULL);
524	if ( shMem ) {
525
526	    register volatile CARD32 *shMemC = shMem;
527	    register int i;
528
529	    gettimeofday( &now, &here);
530	    magic = now.tv_usec & 0x000FFFFF;
531	    req->magic = magic;
532	    i = 1024 / sizeof(CARD32);
533	    while(i--) {
534	        *shMemC++ = magic;
535	        magic = ~magic;
536	    }
537	} else {
538	    req->shmKey = -1;
539	}
540    }
541#else
542    req->shmKey = 0;
543#endif
544    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
545        UnlockDisplay (dpy);
546        SyncHandle ();
547#ifdef HAVE_SHMAT
548	if ( req->shmKey >= 0) {
549	    shmdt( (const void *) shMem );
550	}
551#endif
552        return -1;
553    }
554#ifdef HAVE_SHMAT
555    shmdt( (const void *) shMem );
556#endif
557
558    if (rep.length > 0) {
559	unsigned long realSize = 0;
560	char *tmpBuf = NULL;
561
562	if (rep.length < (INT_MAX >> 2)) {
563	    realSize = rep.length << 2;
564	    if (realSize >= (rep.nameLen + rep.busIDLen)) {
565		tmpBuf = Xmalloc(realSize);
566		*name = Xmalloc(rep.nameLen);
567		*busID = Xmalloc(rep.busIDLen);
568	    }
569	}
570
571	if (*name && *busID && tmpBuf) {
572	    _XRead(dpy, tmpBuf, realSize);
573	    strncpy(*name,tmpBuf,rep.nameLen);
574	    name[rep.nameLen - 1] = '\0';
575	    strncpy(*busID,tmpBuf+rep.nameLen,rep.busIDLen);
576	    busID[rep.busIDLen - 1] = '\0';
577	    XFree(tmpBuf);
578	} else {
579	    XFree(*name);
580	    *name = NULL;
581	    XFree(*busID);
582	    *name = NULL;
583	    XFree(tmpBuf);
584
585	    _XEatData(dpy, realSize);
586	    UnlockDisplay (dpy);
587	    SyncHandle ();
588	    return -1;
589
590	}
591    }
592
593    UnlockDisplay (dpy);
594    SyncHandle ();
595    *major = rep.major;
596    *minor = rep.minor;
597    *patchLevel = rep.patchLevel;
598    *isLocal = (req->shmKey > 0) ? rep.isLocal : 1;
599    return (rep.length > 0) ? Success : BadImplementation;
600}
601
602