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    "BadContext",
27    "BadSurface",
28    "BadSubpicture"
29};
30
31static XEXT_GENERATE_CLOSE_DISPLAY(xvmc_close_display, xvmc_info)
32static XEXT_GENERATE_ERROR_STRING(xvmc_error_string, xvmc_extension_name,
33                                  XvMCNumErrors, xvmc_error_list)
34
35static XExtensionHooks xvmc_extension_hooks = {
36    NULL,                       /* create_gc */
37    NULL,                       /* copy_gc */
38    NULL,                       /* flush_gc */
39    NULL,                       /* free_gc */
40    NULL,                       /* create_font */
41    NULL,                       /* free_font */
42    xvmc_close_display,         /* close_display */
43    NULL,                       /* wire_to_event */
44    NULL,                       /* event_to_wire */
45    NULL,                       /* error */
46    xvmc_error_string           /* error_string */
47};
48
49static XEXT_GENERATE_FIND_DISPLAY(xvmc_find_display, xvmc_info,
50                                  xvmc_extension_name,
51                                  &xvmc_extension_hooks,
52                                  XvMCNumEvents, NULL)
53
54Bool
55XvMCQueryExtension(Display *dpy, int *event_basep, int *error_basep)
56{
57    XExtDisplayInfo *info = xvmc_find_display(dpy);
58
59    if (XextHasExtension(info)) {
60        *event_basep = info->codes->first_event;
61        *error_basep = info->codes->first_error;
62        return True;
63    }
64    else {
65        return False;
66    }
67}
68
69Status
70XvMCQueryVersion(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 = (int) rep.major;
86    *minor = (int) rep.minor;
87    UnlockDisplay(dpy);
88    SyncHandle();
89    return Success;
90}
91
92XvMCSurfaceInfo *
93XvMCListSurfaceTypes(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 = (CARD32) 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        if (rep.num < (INT_MAX / sizeof(XvMCSurfaceInfo)))
115            surface_info = Xmalloc(rep.num * sizeof(XvMCSurfaceInfo));
116
117        if (surface_info) {
118            *num = (int) rep.num;
119
120            for (CARD32 i = 0; i < rep.num; i++) {
121                xvmcSurfaceInfo sinfo;
122
123                _XRead(dpy, (char *) &sinfo, sizeof(xvmcSurfaceInfo));
124                surface_info[i].surface_type_id = (int) sinfo.surface_type_id;
125                surface_info[i].chroma_format = sinfo.chroma_format;
126                surface_info[i].max_width = sinfo.max_width;
127                surface_info[i].max_height = sinfo.max_height;
128                surface_info[i].subpicture_max_width =
129                    sinfo.subpicture_max_width;
130                surface_info[i].subpicture_max_height =
131                    sinfo.subpicture_max_height;
132                surface_info[i].mc_type = (int) sinfo.mc_type;
133                surface_info[i].flags = (int) sinfo.flags;
134            }
135        }
136        else
137            _XEatDataWords(dpy, rep.length);
138    }
139
140    UnlockDisplay(dpy);
141    SyncHandle();
142    return surface_info;
143}
144
145XvImageFormatValues *
146XvMCListSubpictureTypes(Display *dpy,
147                        XvPortID port,
148                        int surface_type_id,
149                        int *count_return)
150{
151    XExtDisplayInfo *info = xvmc_find_display(dpy);
152    xvmcListSubpictureTypesReply rep;
153    xvmcListSubpictureTypesReq  *req;
154    XvImageFormatValues *ret = NULL;
155
156    *count_return = 0;
157
158    XvMCCheckExtension(dpy, info, NULL);
159
160    LockDisplay(dpy);
161    XvMCGetReq(ListSubpictureTypes, req);
162    req->port = (CARD32) port;
163    req->surface_type_id = (CARD32) surface_type_id;
164    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
165        UnlockDisplay(dpy);
166        SyncHandle();
167        return NULL;
168    }
169
170    if (rep.num > 0) {
171        if (rep.num < (INT_MAX / sizeof(XvImageFormatValues)))
172            ret = Xmalloc(rep.num * sizeof(XvImageFormatValues));
173
174        if (ret) {
175            *count_return = (int) rep.num;
176
177            for (CARD32 i = 0; i < rep.num; i++) {
178                xvImageFormatInfo Info;
179
180                _XRead(dpy, (char *) (&Info), sz_xvImageFormatInfo);
181                ret[i].id = (int) Info.id;
182                ret[i].type = Info.type;
183                ret[i].byte_order = Info.byte_order;
184                memcpy(&(ret[i].guid[0]), &(Info.guid[0]), 16);
185                ret[i].bits_per_pixel = Info.bpp;
186                ret[i].format = Info.format;
187                ret[i].num_planes = Info.num_planes;
188                ret[i].depth = Info.depth;
189                ret[i].red_mask = Info.red_mask;
190                ret[i].green_mask = Info.green_mask;
191                ret[i].blue_mask = Info.blue_mask;
192                ret[i].y_sample_bits = Info.y_sample_bits;
193                ret[i].u_sample_bits = Info.u_sample_bits;
194                ret[i].v_sample_bits = Info.v_sample_bits;
195                ret[i].horz_y_period = Info.horz_y_period;
196                ret[i].horz_u_period = Info.horz_u_period;
197                ret[i].horz_v_period = Info.horz_v_period;
198                ret[i].vert_y_period = Info.vert_y_period;
199                ret[i].vert_u_period = Info.vert_u_period;
200                ret[i].vert_v_period = Info.vert_v_period;
201                memcpy(&(ret[i].component_order[0]), &(Info.comp_order[0]), 32);
202                ret[i].scanline_order = Info.scanline_order;
203            }
204        }
205        else
206            _XEatDataWords(dpy, rep.length);
207    }
208
209    UnlockDisplay(dpy);
210    SyncHandle();
211    return ret;
212}
213
214/******************************************************************
215   These are intended as a protocol interface to be used by direct
216   rendering libraries.  They are not intended to be client viewable
217   functions.  These will stay in place until we have a mechanism in
218   place similar to that of OpenGL with an libXvMCcore library.
219*******************************************************************/
220
221/*
222   _xvmc_create_context -
223
224   Pass in the context with the surface_type_id, width, height,
225   port and flags filled out.  This function will fill out the
226   context_id and update the width, height and flags field.
227   The server may return implementation-specific information
228   back in the priv_data.  The size of that information will
229   an array of priv_count CARD32s.  This data is allocated by
230   this function.  If returned, the caller is responsible for
231   freeing it!  Generally, such information is only returned if
232   an XVMC_DIRECT context was specified.
233*/
234
235Status
236_xvmc_create_context(Display *dpy,
237                     XvMCContext *context,
238                     int *priv_count,
239                     CARD32 **priv_data)
240{
241    XExtDisplayInfo *info = xvmc_find_display(dpy);
242    xvmcCreateContextReply rep;
243    xvmcCreateContextReq  *req;
244
245    *priv_count = 0;
246    *priv_data = NULL;
247
248    XvMCCheckExtension(dpy, info, BadImplementation);
249
250    LockDisplay(dpy);
251    XvMCGetReq(CreateContext, req);
252    context->context_id = XAllocID(dpy);
253    req->context_id = (CARD32) context->context_id;
254    req->port =  (CARD32) context->port;
255    req->surface_type_id = (CARD32) context->surface_type_id;
256    req->width = context->width;
257    req->height = context->height;
258    req->flags = (CARD32) context->flags;
259    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
260        UnlockDisplay(dpy);
261        SyncHandle();
262        return BadImplementation;
263    }
264    context->width = rep.width_actual;
265    context->height = rep.height_actual;
266    context->flags = (int) rep.flags_return;
267
268    if (rep.length) {
269        if (rep.length < (INT_MAX >> 2))
270            *priv_data = Xmalloc(rep.length << 2);
271        if (*priv_data) {
272            _XRead(dpy, (char *) (*priv_data), rep.length << 2);
273            *priv_count = (int) rep.length;
274        }
275        else
276            _XEatDataWords(dpy, rep.length);
277    }
278
279    UnlockDisplay(dpy);
280    SyncHandle();
281    return Success;
282}
283
284Status
285_xvmc_destroy_context(Display *dpy, XvMCContext *context)
286{
287    XExtDisplayInfo *info = xvmc_find_display(dpy);
288    xvmcDestroyContextReq  *req;
289
290    XvMCCheckExtension(dpy, info, BadImplementation);
291
292    LockDisplay(dpy);
293    XvMCGetReq(DestroyContext, req);
294    req->context_id = (CARD32) context->context_id;
295    UnlockDisplay(dpy);
296    SyncHandle();
297    return Success;
298}
299
300/*
301   _xvmc_create_surface -
302
303   Pass the context and this function will fill out all the
304   information in the surface.
305   The server may return implementation-specific information
306   back in the priv_data.  The size of that information will
307   an array of priv_count CARD32s.  This data is allocated by
308   this function.  If returned, the caller is responsible for
309   freeing it!  Generally, such information is returned only if
310   the context was a direct context.
311
312*/
313
314Status
315_xvmc_create_surface(Display *dpy,
316                     XvMCContext *context,
317                     XvMCSurface *surface,
318                     int *priv_count,
319                     CARD32 **priv_data)
320{
321    XExtDisplayInfo *info = xvmc_find_display(dpy);
322    xvmcCreateSurfaceReply rep;
323    xvmcCreateSurfaceReq  *req;
324
325    *priv_count = 0;
326    *priv_data = NULL;
327
328    XvMCCheckExtension(dpy, info, BadImplementation);
329
330    LockDisplay(dpy);
331    XvMCGetReq(CreateSurface, req);
332
333    surface->surface_id = XAllocID(dpy);
334    surface->context_id = context->context_id;
335    surface->surface_type_id = context->surface_type_id;
336    surface->width = context->width;
337    surface->height = context->height;
338
339    req->surface_id = (CARD32) surface->surface_id;
340    req->context_id = (CARD32) surface->context_id;
341    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
342        UnlockDisplay(dpy);
343        SyncHandle();
344        return BadImplementation;
345    }
346
347    if (rep.length) {
348        if (rep.length < (INT_MAX >> 2))
349            *priv_data = Xmalloc(rep.length << 2);
350        if (*priv_data) {
351            _XRead(dpy, (char *) (*priv_data), rep.length << 2);
352            *priv_count = (int) rep.length;
353        }
354        else
355            _XEatDataWords(dpy, rep.length);
356    }
357
358    UnlockDisplay(dpy);
359    SyncHandle();
360    return Success;
361}
362
363Status
364_xvmc_destroy_surface(Display *dpy, XvMCSurface *surface)
365{
366    XExtDisplayInfo *info = xvmc_find_display(dpy);
367    xvmcDestroySurfaceReq  *req;
368
369    XvMCCheckExtension(dpy, info, BadImplementation);
370
371    LockDisplay(dpy);
372    XvMCGetReq(DestroySurface, req);
373    req->surface_id = (CARD32) surface->surface_id;
374    UnlockDisplay(dpy);
375    SyncHandle();
376    return Success;
377}
378
379/*
380   _xvmc_create_subpicture -
381
382   Pass the subpicture with the width, height and xvimage_id filled
383   out and this function will fill out everything else in the
384   subpicture as well as adjust the width and height if needed.
385   The server may return implementation-specific information
386   back in the priv_data.  The size of that information will
387   an array of priv_count CARD32s.  This data is allocated by
388   this function.  If returned, the caller is responsible for
389   freeing it!  Generally, such information is returned only if
390   the context was a direct context.
391
392*/
393
394Status
395_xvmc_create_subpicture(Display *dpy,
396                        XvMCContext *context,
397                        XvMCSubpicture *subpicture,
398                        int *priv_count,
399                        CARD32 **priv_data)
400{
401    XExtDisplayInfo *info = xvmc_find_display(dpy);
402    xvmcCreateSubpictureReply rep;
403    xvmcCreateSubpictureReq  *req;
404
405    *priv_count = 0;
406    *priv_data = NULL;
407
408    XvMCCheckExtension(dpy, info, BadImplementation);
409
410    LockDisplay(dpy);
411    XvMCGetReq(CreateSubpicture, req);
412
413    subpicture->subpicture_id = XAllocID(dpy);
414    subpicture->context_id = context->context_id;
415
416    req->subpicture_id = (CARD32) subpicture->subpicture_id;
417    req->context_id = (CARD32) subpicture->context_id;
418    req->xvimage_id = (CARD32) subpicture->xvimage_id;
419    req->width = subpicture->width;
420    req->height = subpicture->height;
421    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
422        UnlockDisplay(dpy);
423        SyncHandle();
424        return BadImplementation;
425    }
426
427    subpicture->width = rep.width_actual;
428    subpicture->height = rep.height_actual;
429    subpicture->num_palette_entries = rep.num_palette_entries;
430    subpicture->entry_bytes = rep.entry_bytes;
431    subpicture->component_order[0] = (char) rep.component_order[0];
432    subpicture->component_order[1] = (char) rep.component_order[1];
433    subpicture->component_order[2] = (char) rep.component_order[2];
434    subpicture->component_order[3] = (char) rep.component_order[3];
435
436    if (rep.length) {
437        if (rep.length < (INT_MAX >> 2))
438            *priv_data = Xmalloc(rep.length << 2);
439        if (*priv_data) {
440            _XRead(dpy, (char *) (*priv_data), rep.length << 2);
441            *priv_count = (int) rep.length;
442        }
443        else
444            _XEatDataWords(dpy, rep.length);
445    }
446
447    UnlockDisplay(dpy);
448    SyncHandle();
449    return Success;
450}
451
452Status
453_xvmc_destroy_subpicture(Display *dpy, XvMCSubpicture *subpicture)
454{
455    XExtDisplayInfo *info = xvmc_find_display(dpy);
456    xvmcDestroySubpictureReq  *req;
457
458    XvMCCheckExtension(dpy, info, BadImplementation);
459
460    LockDisplay(dpy);
461    XvMCGetReq(DestroySubpicture, req);
462    req->subpicture_id = (CARD32) subpicture->subpicture_id;
463    UnlockDisplay(dpy);
464    SyncHandle();
465    return Success;
466}
467
468Status
469XvMCGetDRInfo(Display *dpy, XvPortID port,
470              char **name, char **busID,
471              int *major, int *minor,
472              int *patchLevel,
473              int *isLocal)
474{
475    XExtDisplayInfo *info = xvmc_find_display(dpy);
476    xvmcGetDRInfoReply rep;
477    xvmcGetDRInfoReq  *req;
478
479#ifdef HAVE_SHMAT
480    int shmKey;
481    volatile CARD32 *shMem;
482#endif
483
484    *name = NULL;
485    *busID = NULL;
486
487    XvMCCheckExtension(dpy, info, BadImplementation);
488
489    LockDisplay(dpy);
490    XvMCGetReq(GetDRInfo, req);
491
492    req->port = (CARD32) port;
493    req->magic = 0;
494#ifdef HAVE_SHMAT
495    shmKey = shmget(IPC_PRIVATE, 1024, IPC_CREAT | 0600);
496    req->shmKey = (CARD32) shmKey;
497
498    /*
499     * We fill a shared memory page with a repetitive pattern. If the
500     * X server can read this pattern, we probably have a local connection.
501     * Note that we can trigger the remote X server to read any shared
502     * page on the remote machine, so we shouldn't be able to guess and verify
503     * any complicated data on those pages. That's the explanation of this
504     * otherwise stupid-looking pattern algorithm.
505     */
506
507    if (shmKey >= 0) {
508        shMem = (CARD32 *) shmat(shmKey, NULL, 0);
509        shmctl(shmKey, IPC_RMID, NULL);
510        if (shMem != (void *) -1) {
511
512            register volatile CARD32 *shMemC = shMem;
513            register int i;
514            CARD32 magic;
515            struct timezone here = {0, 0};
516            struct timeval now;
517
518            gettimeofday(&now, &here);
519            magic = now.tv_usec & 0x000FFFFF;
520            req->magic = magic;
521            i = 1024 / sizeof(CARD32);
522            while (i--) {
523                *shMemC++ = magic;
524                magic = ~magic;
525            }
526        }
527        else {
528            req->shmKey = (CARD32) -1;
529            shmKey = -1;
530        }
531    }
532#else
533    req->shmKey = 0;
534#endif
535    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
536        UnlockDisplay(dpy);
537        SyncHandle();
538#ifdef HAVE_SHMAT
539        if (shmKey >= 0) {
540            shmdt((const void *) shMem);
541        }
542#endif
543        return -1;
544    }
545#ifdef HAVE_SHMAT
546    if (shmKey >= 0) {
547        shmdt((const void *) shMem);
548    }
549#endif
550
551    if (rep.length > 0) {
552        unsigned long realSize = 0;
553        char *tmpBuf = NULL;
554
555        if ((rep.length < (INT_MAX >> 2)) &&
556            /* protect against overflow in strncpy below */
557            (rep.nameLen + rep.busIDLen > rep.nameLen)) {
558            realSize = rep.length << 2;
559            if (realSize >= (rep.nameLen + rep.busIDLen)) {
560                tmpBuf = Xmalloc(realSize);
561                *name = Xmalloc(rep.nameLen);
562                *busID = Xmalloc(rep.busIDLen);
563            }
564        }
565
566        if (*name && *busID && tmpBuf) {
567            _XRead(dpy, tmpBuf, (long) realSize);
568            strncpy(*name, tmpBuf, rep.nameLen);
569            (*name)[rep.nameLen == 0 ? 0 : rep.nameLen - 1] = '\0';
570            strncpy(*busID, tmpBuf + rep.nameLen, rep.busIDLen);
571            (*busID)[rep.busIDLen == 0 ? 0 : rep.busIDLen - 1] = '\0';
572            XFree(tmpBuf);
573        }
574        else {
575            XFree(*name);
576            *name = NULL;
577            XFree(*busID);
578            *busID = NULL;
579            XFree(tmpBuf);
580
581            _XEatDataWords(dpy, rep.length);
582            UnlockDisplay(dpy);
583            SyncHandle();
584            return -1;
585
586        }
587    }
588
589    UnlockDisplay(dpy);
590    SyncHandle();
591    *major = (int) rep.major;
592    *minor = (int) rep.minor;
593    *patchLevel = (int) rep.patchLevel;
594#ifdef HAVE_SHMAT
595    if (shmKey >= 0)
596        *isLocal = (int) rep.isLocal;
597    else
598#endif
599        *isLocal = 1;
600    return (rep.length > 0) ? Success : BadImplementation;
601}
602