Xv.c revision 949d0342
1/***********************************************************
2Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts,
3and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
4
5                        All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Digital or MIT not be
12used in advertising or publicity pertaining to distribution of the
13software without specific, written prior permission.
14
15DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
16ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
17DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
18ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
20ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
21SOFTWARE.
22
23******************************************************************/
24/*
25** File:
26**
27**   Xv.c --- Xv library extension module.
28**
29** Author:
30**
31**   David Carver (Digital Workstation Engineering/Project Athena)
32**
33** Revisions:
34**
35**   26.06.91 Carver
36**     - changed XvFreeAdaptors to XvFreeAdaptorInfo
37**     - changed XvFreeEncodings to XvFreeEncodingInfo
38**
39**   11.06.91 Carver
40**     - changed SetPortControl to SetPortAttribute
41**     - changed GetPortControl to GetPortAttribute
42**     - changed QueryBestSize
43**
44**   15.05.91 Carver
45**     - version 2.0 upgrade
46**
47**   240.01.91 Carver
48**     - version 1.4 upgrade
49**
50*/
51
52#ifdef HAVE_CONFIG_H
53# include "config.h"
54#endif
55
56#include <stdio.h>
57#include "Xvlibint.h"
58#include <X11/extensions/Xext.h>
59#include <X11/extensions/extutil.h>
60#include <X11/extensions/XShm.h>
61#include <limits.h>
62
63static XExtensionInfo _xv_info_data;
64static XExtensionInfo *xv_info = &_xv_info_data;
65static const char *xv_extension_name = XvName;
66
67#define XvCheckExtension(dpy, i, val) \
68  XextCheckExtension(dpy, i, xv_extension_name, val)
69
70#define pad_to_int32(bytes) (((bytes) + 3) & ~3U)
71
72static char *xv_error_string(Display *dpy, int code, XExtCodes *codes,
73                             char *buf, int n);
74static int xv_close_display(Display *dpy, XExtCodes *codes);
75static Bool xv_wire_to_event(Display *dpy, XEvent *host, xEvent *wire);
76
77static XExtensionHooks xv_extension_hooks = {
78    NULL,                       /* create_gc */
79    NULL,                       /* copy_gc */
80    NULL,                       /* flush_gc */
81    NULL,                       /* free_gc */
82    NULL,                       /* create_font */
83    NULL,                       /* free_font */
84    xv_close_display,           /* close_display */
85    xv_wire_to_event,           /* wire_to_event */
86    NULL,                       /* event_to_wire */
87    NULL,                       /* error */
88    xv_error_string             /* error_string */
89};
90
91
92static const char *xv_error_list[] = {
93    "BadPort",                  /* XvBadPort     */
94    "BadEncoding",              /* XvBadEncoding */
95    "BadControl"                /* XvBadControl  */
96};
97
98static XEXT_GENERATE_CLOSE_DISPLAY(xv_close_display, xv_info)
99
100static XEXT_GENERATE_FIND_DISPLAY(xv_find_display, xv_info,
101				  xv_extension_name, &xv_extension_hooks,
102				  XvNumEvents, NULL)
103
104static XEXT_GENERATE_ERROR_STRING(xv_error_string, xv_extension_name,
105				  XvNumErrors, xv_error_list)
106
107
108int
109XvQueryExtension(
110    Display *dpy,
111    unsigned int *p_version,
112    unsigned int *p_revision,
113    unsigned int *p_requestBase,
114    unsigned int *p_eventBase,
115    unsigned int *p_errorBase)
116{
117    XExtDisplayInfo *info = xv_find_display(dpy);
118    xvQueryExtensionReq *req;
119    xvQueryExtensionReply rep;
120    int status;
121
122    XvCheckExtension(dpy, info, XvBadExtension);
123
124    LockDisplay(dpy);
125
126    XvGetReq(QueryExtension, req);
127
128    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
129        status = XvBadExtension;
130        goto out;
131    }
132
133    *p_version = rep.version;
134    *p_revision = rep.revision;
135    *p_requestBase = (unsigned int) info->codes->major_opcode;
136    *p_eventBase = (unsigned int) info->codes->first_event;
137    *p_errorBase = (unsigned int) info->codes->first_error;
138
139    status = Success;
140
141  out:
142    UnlockDisplay(dpy);
143    SyncHandle();
144
145    return status;
146}
147
148int
149XvQueryAdaptors(
150    Display *dpy,
151    Window window,
152    unsigned int *p_nAdaptors,
153    XvAdaptorInfo **p_pAdaptors)
154{
155    XExtDisplayInfo *info = xv_find_display(dpy);
156    xvQueryAdaptorsReq *req;
157    xvQueryAdaptorsReply rep;
158    size_t size;
159    XvAdaptorInfo *pas = NULL, *pa;
160    XvFormat *pfs, *pf;
161    char *buffer = NULL;
162    char *end;
163    union {
164        char *buffer;
165        char *string;
166        xvAdaptorInfo *pa;
167        xvFormat *pf;
168    } u;
169    int status;
170
171    XvCheckExtension(dpy, info, XvBadExtension);
172
173    LockDisplay(dpy);
174
175    XvGetReq(QueryAdaptors, req);
176    req->window = (CARD32) window;
177
178    /* READ THE REPLY */
179
180    if (_XReply(dpy, (xReply *) &rep, 0, xFalse) == 0) {
181        rep.num_adaptors = 0;
182        status = XvBadReply;
183        goto out;
184    }
185
186    size = rep.length << 2;
187    if (size > 0) {
188        if ((buffer = Xmalloc(size)) == NULL) {
189            _XEatDataWords(dpy, rep.length);
190            status = XvBadAlloc;
191            goto out;
192        }
193        _XRead(dpy, buffer, (long) size);
194    }
195
196    /* GET INPUT ADAPTORS */
197
198    if (rep.num_adaptors == 0) {
199        /* If there are no adaptors, there's nothing more to do. */
200        status = Success;
201        goto out;
202    }
203
204    u.buffer = buffer;
205    end = buffer + size;
206
207    size = rep.num_adaptors * sizeof(XvAdaptorInfo);
208    if ((pas = Xmalloc(size)) == NULL) {
209        status = XvBadAlloc;
210        goto out;
211    }
212
213    /* INIT ADAPTOR FIELDS */
214
215    pa = pas;
216    for (unsigned int ii = 0; ii < rep.num_adaptors; ii++) {
217        pa->num_adaptors = 0;
218        pa->name = (char *) NULL;
219        pa->formats = (XvFormat *) NULL;
220        pa++;
221    }
222
223    pa = pas;
224    for (unsigned int ii = 0; ii < rep.num_adaptors; ii++) {
225        char *name;
226
227        if (u.buffer + sz_xvAdaptorInfo > end) {
228            status = XvBadReply;
229            goto out;
230        }
231        pa->type = (char) u.pa->type;
232        pa->base_id = u.pa->base_id;
233        pa->num_ports = u.pa->num_ports;
234        pa->num_formats = u.pa->num_formats;
235        pa->num_adaptors = rep.num_adaptors - ii;
236
237        /* GET ADAPTOR NAME */
238
239        size = u.pa->name_size;
240        u.buffer += pad_to_int32(sz_xvAdaptorInfo);
241
242        if (u.buffer + size > end) {
243            status = XvBadReply;
244            goto out;
245        }
246        if ((name = Xmalloc(size + 1)) == NULL) {
247            status = XvBadAlloc;
248            goto out;
249        }
250        (void) strncpy(name, u.string, size);
251        name[size] = '\0';
252        pa->name = name;
253
254        u.buffer += pad_to_int32(size);
255
256        /* GET FORMATS */
257
258        size = pa->num_formats * sizeof(XvFormat);
259        if ((pfs = Xmalloc(size)) == NULL) {
260            status = XvBadAlloc;
261            goto out;
262        }
263
264        pf = pfs;
265        for (unsigned int jj = 0; jj < pa->num_formats; jj++) {
266            if (u.buffer + sz_xvFormat > end) {
267                Xfree(pfs);
268                status = XvBadReply;
269                goto out;
270            }
271            pf->depth = (char) u.pf->depth;
272            pf->visual_id = u.pf->visual;
273            pf++;
274
275            u.buffer += pad_to_int32(sz_xvFormat);
276        }
277
278        pa->formats = pfs;
279
280        pa++;
281
282    }
283
284    status = Success;
285
286  out:
287    if (status != Success) {
288        XvFreeAdaptorInfo(pas);
289        pas = NULL;
290    }
291
292    *p_nAdaptors = rep.num_adaptors;
293    *p_pAdaptors = pas;
294
295    Xfree(buffer);
296    UnlockDisplay(dpy);
297    SyncHandle();
298
299    return status;
300}
301
302
303void
304XvFreeAdaptorInfo(XvAdaptorInfo *pAdaptors)
305{
306    XvAdaptorInfo *pa;
307
308    if (!pAdaptors)
309        return;
310
311    pa = pAdaptors;
312
313    for (unsigned int ii = 0; ii < pAdaptors->num_adaptors; ii++, pa++) {
314        if (pa->name) {
315            Xfree(pa->name);
316        }
317        if (pa->formats) {
318            Xfree(pa->formats);
319        }
320    }
321
322    Xfree(pAdaptors);
323}
324
325int
326XvQueryEncodings(
327    Display *dpy,
328    XvPortID port,
329    unsigned int *p_nEncodings,
330    XvEncodingInfo ** p_pEncodings)
331{
332    XExtDisplayInfo *info = xv_find_display(dpy);
333    xvQueryEncodingsReq *req;
334    xvQueryEncodingsReply rep;
335    size_t size;
336    XvEncodingInfo *pes = NULL, *pe;
337    char *buffer = NULL;
338    char *end;
339    union {
340        char *buffer;
341        char *string;
342        xvEncodingInfo *pe;
343    } u;
344    int status;
345
346    XvCheckExtension(dpy, info, XvBadExtension);
347
348    LockDisplay(dpy);
349
350    XvGetReq(QueryEncodings, req);
351    req->port = (CARD32) port;
352
353    /* READ THE REPLY */
354
355    if (_XReply(dpy, (xReply *) &rep, 0, xFalse) == 0) {
356        rep.num_encodings = 0;
357        status = XvBadReply;
358        goto out;
359    }
360
361    size = rep.length << 2;
362    if (size > 0) {
363        if ((buffer = Xmalloc(size)) == NULL) {
364            _XEatDataWords(dpy, rep.length);
365            status = XvBadAlloc;
366            goto out;
367        }
368        _XRead(dpy, buffer, (long) size);
369    }
370
371    /* GET ENCODINGS */
372
373    if (rep.num_encodings == 0) {
374        /* If there are no encodings, there's nothing more to do. */
375        status = Success;
376        goto out;
377    }
378
379    u.buffer = buffer;
380    end = buffer + size;
381
382    size = rep.num_encodings * sizeof(XvEncodingInfo);
383    if ((pes = Xmalloc(size)) == NULL) {
384        status = XvBadAlloc;
385        goto out;
386    }
387
388    /* INITIALIZE THE ENCODING POINTER */
389
390    pe = pes;
391    for (unsigned int jj = 0; jj < rep.num_encodings; jj++) {
392        pe->name = (char *) NULL;
393        pe->num_encodings = 0;
394        pe++;
395    }
396
397    pe = pes;
398    for (unsigned int jj = 0; jj < rep.num_encodings; jj++) {
399        char *name;
400
401        if (u.buffer + sz_xvEncodingInfo > end) {
402            status = XvBadReply;
403            goto out;
404        }
405        pe->encoding_id = u.pe->encoding;
406        pe->width = u.pe->width;
407        pe->height = u.pe->height;
408        pe->rate.numerator = u.pe->rate.numerator;
409        pe->rate.denominator = u.pe->rate.denominator;
410        pe->num_encodings = rep.num_encodings - jj;
411
412        size = u.pe->name_size;
413        u.buffer += pad_to_int32(sz_xvEncodingInfo);
414
415        if (u.buffer + size > end) {
416            status = XvBadReply;
417            goto out;
418        }
419        if ((name = Xmalloc(size + 1)) == NULL) {
420            status = XvBadAlloc;
421            goto out;
422        }
423        strncpy(name, u.string, size);
424        name[size] = '\0';
425        pe->name = name;
426        pe++;
427
428        u.buffer += pad_to_int32(size);
429    }
430
431    status = Success;
432
433  out:
434    if (status != Success) {
435        XvFreeEncodingInfo(pes);
436        pes = NULL;
437    }
438
439    *p_nEncodings = rep.num_encodings;
440    *p_pEncodings = pes;
441
442    Xfree(buffer);
443    UnlockDisplay(dpy);
444    SyncHandle();
445
446    return (Success);
447}
448
449void
450XvFreeEncodingInfo(XvEncodingInfo *pEncodings)
451{
452    XvEncodingInfo *pe;
453
454    if (!pEncodings)
455        return;
456
457    pe = pEncodings;
458
459    for (unsigned long ii = 0; ii < pEncodings->num_encodings; ii++, pe++) {
460        if (pe->name)
461            Xfree(pe->name);
462    }
463
464    Xfree(pEncodings);
465}
466
467int
468XvPutVideo(
469    Display *dpy,
470    XvPortID port,
471    Drawable d,
472    GC gc,
473    int vx, int vy,
474    unsigned int vw, unsigned int vh,
475    int dx, int dy,
476    unsigned int dw, unsigned int dh)
477{
478    XExtDisplayInfo *info = xv_find_display(dpy);
479    xvPutVideoReq *req;
480
481    XvCheckExtension(dpy, info, XvBadExtension);
482
483    LockDisplay(dpy);
484
485    FlushGC(dpy, gc);
486
487    XvGetReq(PutVideo, req);
488
489    req->port = (CARD32) port;
490    req->drawable = (CARD32) d;
491    req->gc = (CARD32) gc->gid;
492    req->vid_x = (INT16) vx;
493    req->vid_y = (INT16) vy;
494    req->vid_w = (CARD16) vw;
495    req->vid_h = (CARD16) vh;
496    req->drw_x = (INT16) dx;
497    req->drw_y = (INT16) dy;
498    req->drw_w = (CARD16) dw;
499    req->drw_h = (CARD16) dh;
500
501    UnlockDisplay(dpy);
502    SyncHandle();
503
504    return Success;
505}
506
507int
508XvPutStill(
509    Display *dpy,
510    XvPortID port,
511    Drawable d,
512    GC gc,
513    int vx, int vy,
514    unsigned int vw, unsigned int vh,
515    int dx, int dy,
516    unsigned int dw, unsigned int dh)
517{
518    XExtDisplayInfo *info = xv_find_display(dpy);
519    xvPutStillReq *req;
520
521    XvCheckExtension(dpy, info, XvBadExtension);
522
523    LockDisplay(dpy);
524
525    FlushGC(dpy, gc);
526
527    XvGetReq(PutStill, req);
528    req->port = (CARD32) port;
529    req->drawable = (CARD32) d;
530    req->gc = (CARD32) gc->gid;
531    req->vid_x = (INT16) vx;
532    req->vid_y = (INT16) vy;
533    req->vid_w = (CARD16) vw;
534    req->vid_h = (CARD16) vh;
535    req->drw_x = (INT16) dx;
536    req->drw_y = (INT16) dy;
537    req->drw_w = (CARD16) dw;
538    req->drw_h = (CARD16) dh;
539
540    UnlockDisplay(dpy);
541    SyncHandle();
542
543    return Success;
544}
545
546int
547XvGetVideo(
548    Display *dpy,
549    XvPortID port,
550    Drawable d,
551    GC gc,
552    int vx, int vy,
553    unsigned int vw, unsigned int vh,
554    int dx, int dy,
555    unsigned int dw, unsigned int dh)
556{
557    XExtDisplayInfo *info = xv_find_display(dpy);
558    xvGetVideoReq *req;
559
560    XvCheckExtension(dpy, info, XvBadExtension);
561
562    LockDisplay(dpy);
563
564    FlushGC(dpy, gc);
565
566    XvGetReq(GetVideo, req);
567    req->port = (CARD32) port;
568    req->drawable = (CARD32) d;
569    req->gc = (CARD32) gc->gid;
570    req->vid_x = (INT16) vx;
571    req->vid_y = (INT16) vy;
572    req->vid_w = (CARD16) vw;
573    req->vid_h = (CARD16) vh;
574    req->drw_x = (INT16) dx;
575    req->drw_y = (INT16) dy;
576    req->drw_w = (CARD16) dw;
577    req->drw_h = (CARD16) dh;
578
579    UnlockDisplay(dpy);
580    SyncHandle();
581
582    return Success;
583}
584
585int
586XvGetStill(
587    Display *dpy,
588    XvPortID port,
589    Drawable d,
590    GC gc,
591    int vx, int vy,
592    unsigned int vw, unsigned int vh,
593    int dx, int dy,
594    unsigned int dw, unsigned int dh)
595{
596    XExtDisplayInfo *info = xv_find_display(dpy);
597    xvGetStillReq *req;
598
599    XvCheckExtension(dpy, info, XvBadExtension);
600
601    LockDisplay(dpy);
602
603    FlushGC(dpy, gc);
604
605    XvGetReq(GetStill, req);
606    req->port = (CARD32) port;
607    req->drawable = (CARD32) d;
608    req->gc = (CARD32) gc->gid;
609    req->vid_x = (INT16) vx;
610    req->vid_y = (INT16) vy;
611    req->vid_w = (CARD16) vw;
612    req->vid_h = (CARD16) vh;
613    req->drw_x = (INT16) dx;
614    req->drw_y = (INT16) dy;
615    req->drw_w = (CARD16) dw;
616    req->drw_h = (CARD16) dh;
617
618    UnlockDisplay(dpy);
619    SyncHandle();
620
621    return Success;
622}
623
624int
625XvStopVideo(Display *dpy, XvPortID port, Drawable draw)
626{
627    XExtDisplayInfo *info = xv_find_display(dpy);
628    xvStopVideoReq *req;
629
630    XvCheckExtension(dpy, info, XvBadExtension);
631
632    LockDisplay(dpy);
633
634    XvGetReq(StopVideo, req);
635    req->port = (CARD32) port;
636    req->drawable = (CARD32) draw;
637
638    UnlockDisplay(dpy);
639    SyncHandle();
640
641    return Success;
642}
643
644int
645XvGrabPort(Display *dpy, XvPortID port, Time time)
646{
647    XExtDisplayInfo *info = xv_find_display(dpy);
648    int result;
649    xvGrabPortReply rep;
650    xvGrabPortReq *req;
651
652    XvCheckExtension(dpy, info, XvBadExtension);
653
654    LockDisplay(dpy);
655
656    XvGetReq(GrabPort, req);
657    req->port = (CARD32) port;
658    req->time = (CARD32) time;
659
660    if (_XReply(dpy, (xReply *) &rep, 0, xTrue) == 0)
661        rep.result = GrabSuccess;
662
663    result = rep.result;
664
665    UnlockDisplay(dpy);
666    SyncHandle();
667
668    return result;
669}
670
671int
672XvUngrabPort(Display *dpy, XvPortID port, Time time)
673{
674    XExtDisplayInfo *info = xv_find_display(dpy);
675    xvUngrabPortReq *req;
676
677    XvCheckExtension(dpy, info, XvBadExtension);
678
679    LockDisplay(dpy);
680
681    XvGetReq(UngrabPort, req);
682    req->port = (CARD32) port;
683    req->time = (CARD32) time;
684
685    UnlockDisplay(dpy);
686    SyncHandle();
687
688    return Success;
689}
690
691int
692XvSelectVideoNotify(Display *dpy, Drawable drawable, Bool onoff)
693{
694    XExtDisplayInfo *info = xv_find_display(dpy);
695    xvSelectVideoNotifyReq *req;
696
697    XvCheckExtension(dpy, info, XvBadExtension);
698
699    LockDisplay(dpy);
700
701    XvGetReq(SelectVideoNotify, req);
702    req->drawable = (CARD32) drawable;
703    req->onoff = (BOOL) onoff;
704
705    UnlockDisplay(dpy);
706    SyncHandle();
707
708    return Success;
709}
710
711int
712XvSelectPortNotify(Display *dpy, XvPortID port, Bool onoff)
713{
714    XExtDisplayInfo *info = xv_find_display(dpy);
715    xvSelectPortNotifyReq *req;
716
717    XvCheckExtension(dpy, info, XvBadExtension);
718
719    LockDisplay(dpy);
720
721    XvGetReq(SelectPortNotify, req);
722    req->port = (CARD32) port;
723    req->onoff = (BOOL) onoff;
724
725    UnlockDisplay(dpy);
726    SyncHandle();
727
728    return Success;
729}
730
731int
732XvSetPortAttribute(Display *dpy, XvPortID port, Atom attribute, int value)
733{
734    XExtDisplayInfo *info = xv_find_display(dpy);
735    xvSetPortAttributeReq *req;
736
737    XvCheckExtension(dpy, info, XvBadExtension);
738
739    LockDisplay(dpy);
740
741    XvGetReq(SetPortAttribute, req);
742    req->port = (CARD32) port;
743    req->attribute = (CARD32) attribute;
744    req->value = value;
745
746    UnlockDisplay(dpy);
747    SyncHandle();
748
749    return (Success);
750}
751
752int
753XvGetPortAttribute(Display *dpy, XvPortID port, Atom attribute, int *p_value)
754{
755    XExtDisplayInfo *info = xv_find_display(dpy);
756    xvGetPortAttributeReq *req;
757    xvGetPortAttributeReply rep;
758    int status;
759
760    XvCheckExtension(dpy, info, XvBadExtension);
761
762    LockDisplay(dpy);
763
764    XvGetReq(GetPortAttribute, req);
765    req->port = (CARD32) port;
766    req->attribute = (CARD32) attribute;
767
768    /* READ THE REPLY */
769
770    if (_XReply(dpy, (xReply *) &rep, 0, xFalse) == 0) {
771        status = XvBadReply;
772    }
773    else {
774        *p_value = rep.value;
775        status = Success;
776    }
777
778    UnlockDisplay(dpy);
779    SyncHandle();
780
781    return status;
782}
783
784int
785XvQueryBestSize(
786    Display *dpy,
787    XvPortID port,
788    Bool motion,
789    unsigned int vid_w,
790    unsigned int vid_h,
791    unsigned int drw_w,
792    unsigned int drw_h,
793    unsigned int *p_actual_width,
794    unsigned int *p_actual_height)
795{
796    XExtDisplayInfo *info = xv_find_display(dpy);
797    xvQueryBestSizeReq *req;
798    xvQueryBestSizeReply rep;
799    int status;
800
801    XvCheckExtension(dpy, info, XvBadExtension);
802
803    LockDisplay(dpy);
804
805    XvGetReq(QueryBestSize, req);
806    req->port = (CARD32) port;
807    req->motion = (CARD8) motion;
808    req->vid_w = (CARD16) vid_w;
809    req->vid_h = (CARD16) vid_h;
810    req->drw_w = (CARD16) drw_w;
811    req->drw_h = (CARD16) drw_h;
812
813    /* READ THE REPLY */
814
815    if (_XReply(dpy, (xReply *) &rep, 0, xFalse) == 0) {
816        status = XvBadReply;
817    }
818    else {
819        *p_actual_width = rep.actual_width;
820        *p_actual_height = rep.actual_height;
821        status = Success;
822    }
823
824    UnlockDisplay(dpy);
825    SyncHandle();
826
827    return status;
828}
829
830
831XvAttribute *
832XvQueryPortAttributes(Display *dpy, XvPortID port, int *num)
833{
834    XExtDisplayInfo *info = xv_find_display(dpy);
835    xvQueryPortAttributesReq *req;
836    xvQueryPortAttributesReply rep;
837    XvAttribute *ret = NULL;
838
839    *num = 0;
840
841    XvCheckExtension(dpy, info, NULL);
842
843    LockDisplay(dpy);
844
845    XvGetReq(QueryPortAttributes, req);
846    req->port = (CARD32) port;
847
848    /* READ THE REPLY */
849
850    if (_XReply(dpy, (xReply *) &rep, 0, xFalse) == 0) {
851        goto out;
852    }
853
854    /*
855     * X server sends data packed as:
856     *   attribute1, name1, attribute2, name2, ...
857     * We allocate a single buffer large enough to hold them all and
858     * then de-interleave the data so we return it to clients as:
859     *   attribute1, attribute2, ..., name1, name2, ...
860     * so that clients may refer to attributes as a simple array of
861     * structs:  attributes[0], attributes[1], ...
862     * and free it as a single/simple buffer.
863     */
864
865    if (rep.num_attributes) {
866        /* limit each part to no more than one half the max size */
867        if ((rep.num_attributes < ((INT_MAX / 2) / sizeof(XvAttribute))) &&
868            (rep.text_size < (INT_MAX / 2) - 1)) {
869            unsigned long size;
870
871            size = (rep.num_attributes * sizeof(XvAttribute)) +
872		rep.text_size + 1;
873            ret = Xmalloc(size);
874        }
875
876        if (ret != NULL) {
877            char *marker = (char *) (&ret[rep.num_attributes]);
878            xvAttributeInfo Info;
879
880            /* keep track of remaining room for text strings */
881            unsigned long size = rep.text_size;
882
883            for (unsigned int i = 0; i < rep.num_attributes; i++) {
884                _XRead(dpy, (char *) (&Info), sz_xvAttributeInfo);
885                ret[i].flags = (int) Info.flags;
886                ret[i].min_value = Info.min;
887                ret[i].max_value = Info.max;
888                ret[i].name = marker;
889                if (Info.size <= size) {
890                    _XRead(dpy, marker, Info.size);
891                    marker += Info.size;
892                    size -= Info.size;
893                }
894                (*num)++;
895            }
896
897            /* ensure final string is nil-terminated to avoid exposure of
898               uninitialized memory */
899            *marker = '\0';
900        }
901        else
902            _XEatDataWords(dpy, rep.length);
903    }
904
905  out:
906    UnlockDisplay(dpy);
907    SyncHandle();
908
909    return ret;
910}
911
912XvImageFormatValues *
913XvListImageFormats(Display *dpy, XvPortID port, int *num)
914{
915    XExtDisplayInfo *info = xv_find_display(dpy);
916    xvListImageFormatsReq *req;
917    xvListImageFormatsReply rep;
918    XvImageFormatValues *ret = NULL;
919
920    *num = 0;
921
922    XvCheckExtension(dpy, info, NULL);
923
924    LockDisplay(dpy);
925
926    XvGetReq(ListImageFormats, req);
927    req->port = (CARD32) port;
928
929    /* READ THE REPLY */
930
931    if (_XReply(dpy, (xReply *) &rep, 0, xFalse) == 0) {
932        goto out;
933    }
934
935    if (rep.num_formats) {
936        if (rep.num_formats < (INT_MAX / sizeof(XvImageFormatValues)))
937            ret = Xmalloc(rep.num_formats * sizeof(XvImageFormatValues));
938
939        if (ret != NULL) {
940            for (unsigned int i = 0; i < rep.num_formats; i++) {
941                xvImageFormatInfo Info;
942
943                _XRead(dpy, (char *) (&Info), sz_xvImageFormatInfo);
944                ret[i].id = (int) Info.id;
945                ret[i].type = Info.type;
946                ret[i].byte_order = Info.byte_order;
947                memcpy(&(ret[i].guid[0]), &(Info.guid[0]), 16);
948                ret[i].bits_per_pixel = Info.bpp;
949                ret[i].format = Info.format;
950                ret[i].num_planes = Info.num_planes;
951                ret[i].depth = Info.depth;
952                ret[i].red_mask = Info.red_mask;
953                ret[i].green_mask = Info.green_mask;
954                ret[i].blue_mask = Info.blue_mask;
955                ret[i].y_sample_bits = Info.y_sample_bits;
956                ret[i].u_sample_bits = Info.u_sample_bits;
957                ret[i].v_sample_bits = Info.v_sample_bits;
958                ret[i].horz_y_period = Info.horz_y_period;
959                ret[i].horz_u_period = Info.horz_u_period;
960                ret[i].horz_v_period = Info.horz_v_period;
961                ret[i].vert_y_period = Info.vert_y_period;
962                ret[i].vert_u_period = Info.vert_u_period;
963                ret[i].vert_v_period = Info.vert_v_period;
964                memcpy(&(ret[i].component_order[0]), &(Info.comp_order[0]), 32);
965                ret[i].scanline_order = Info.scanline_order;
966                (*num)++;
967            }
968        }
969        else
970            _XEatDataWords(dpy, rep.length);
971    }
972
973  out:
974    UnlockDisplay(dpy);
975    SyncHandle();
976
977    return ret;
978}
979
980XvImage *
981XvCreateImage(
982    Display *dpy,
983    XvPortID port,
984    int id,
985    char *data,
986    int width,
987    int height)
988{
989    XExtDisplayInfo *info = xv_find_display(dpy);
990    xvQueryImageAttributesReq *req;
991    xvQueryImageAttributesReply rep;
992    XvImage *ret = NULL;
993
994    XvCheckExtension(dpy, info, NULL);
995
996    LockDisplay(dpy);
997
998    XvGetReq(QueryImageAttributes, req);
999    req->id = (CARD32) id;
1000    req->port = (CARD32) port;
1001    req->width = (CARD16) width;
1002    req->height = (CARD16) height;
1003
1004    /* READ THE REPLY */
1005
1006    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
1007        goto out;
1008    }
1009
1010    if (rep.num_planes < ((INT_MAX >> 3) - sizeof(XvImage)))
1011        ret = Xmalloc(sizeof(XvImage) + (rep.num_planes << 3));
1012
1013    if (ret != NULL) {
1014        ret->id = id;
1015        ret->width = rep.width;
1016        ret->height = rep.height;
1017        ret->data_size = (int) rep.data_size;
1018        ret->num_planes = (int) rep.num_planes;
1019        ret->pitches = (int *) (&ret[1]);
1020        ret->offsets = ret->pitches + rep.num_planes;
1021        ret->data = data;
1022        ret->obdata = NULL;
1023        _XRead(dpy, (char *) (ret->pitches), rep.num_planes << 2);
1024        _XRead(dpy, (char *) (ret->offsets), rep.num_planes << 2);
1025    }
1026    else
1027        _XEatDataWords(dpy, rep.length);
1028
1029  out:
1030    UnlockDisplay(dpy);
1031    SyncHandle();
1032
1033    return ret;
1034}
1035
1036XvImage *
1037XvShmCreateImage(
1038    Display *dpy,
1039    XvPortID port,
1040    int id,
1041    char *data,
1042    int width,
1043    int height,
1044    XShmSegmentInfo *shminfo)
1045{
1046    XvImage *ret;
1047
1048    ret = XvCreateImage(dpy, port, id, data, width, height);
1049
1050    if (ret)
1051        ret->obdata = (XPointer) shminfo;
1052
1053    return ret;
1054}
1055
1056int
1057XvPutImage(
1058    Display *dpy,
1059    XvPortID port,
1060    Drawable d,
1061    GC gc,
1062    XvImage *image,
1063    int src_x, int src_y,
1064    unsigned int src_w, unsigned int src_h,
1065    int dest_x, int dest_y,
1066    unsigned int dest_w, unsigned int dest_h)
1067{
1068    XExtDisplayInfo *info = xv_find_display(dpy);
1069    xvPutImageReq *req;
1070    unsigned int len;
1071
1072    XvCheckExtension(dpy, info, XvBadExtension);
1073
1074    LockDisplay(dpy);
1075
1076    FlushGC(dpy, gc);
1077
1078    XvGetReq(PutImage, req);
1079
1080    req->port = (CARD32) port;
1081    req->drawable = (CARD32) d;
1082    req->gc = (CARD32) gc->gid;
1083    req->id = (CARD32) image->id;
1084    req->src_x = (INT16) src_x;
1085    req->src_y = (INT16) src_y;
1086    req->src_w = (CARD16) src_w;
1087    req->src_h = (CARD16) src_h;
1088    req->drw_x = (INT16) dest_x;
1089    req->drw_y = (INT16) dest_y;
1090    req->drw_w = (CARD16) dest_w;
1091    req->drw_h = (CARD16) dest_h;
1092    req->width = (CARD16) image->width;
1093    req->height = (CARD16) image->height;
1094
1095    len = ((unsigned int) image->data_size + 3) >> 2;
1096    SetReqLen(req, len, len);
1097
1098    /* Yes it's kindof lame that we are sending the whole thing,
1099       but for video all of it may be needed even if displaying
1100       only a subsection, and I don't want to go through the
1101       trouble of creating subregions to send */
1102    Data(dpy, (char *) image->data, image->data_size);
1103
1104    UnlockDisplay(dpy);
1105    SyncHandle();
1106
1107    return Success;
1108}
1109
1110int
1111XvShmPutImage(
1112    Display *dpy,
1113    XvPortID port,
1114    Drawable d,
1115    GC gc,
1116    XvImage *image,
1117    int src_x, int src_y,
1118    unsigned int src_w, unsigned int src_h,
1119    int dest_x, int dest_y,
1120    unsigned int dest_w, unsigned int dest_h,
1121    Bool send_event)
1122{
1123    XExtDisplayInfo *info = xv_find_display(dpy);
1124    XShmSegmentInfo *shminfo = (XShmSegmentInfo *) image->obdata;
1125    xvShmPutImageReq *req;
1126
1127    XvCheckExtension(dpy, info, XvBadExtension);
1128
1129    LockDisplay(dpy);
1130
1131    FlushGC(dpy, gc);
1132
1133    XvGetReq(ShmPutImage, req);
1134
1135    req->port = (CARD32) port;
1136    req->drawable = (CARD32) d;
1137    req->gc = (CARD32) gc->gid;
1138    req->shmseg = (CARD32) shminfo->shmseg;
1139    req->id = (CARD32) image->id;
1140    req->src_x = (INT16) src_x;
1141    req->src_y = (INT16) src_y;
1142    req->src_w = (CARD16) src_w;
1143    req->src_h = (CARD16) src_h;
1144    req->drw_x = (INT16) dest_x;
1145    req->drw_y = (INT16) dest_y;
1146    req->drw_w = (CARD16) dest_w;
1147    req->drw_h = (CARD16) dest_h;
1148    req->offset = (CARD32) (image->data - shminfo->shmaddr);
1149    req->width = (CARD16) image->width;
1150    req->height = (CARD16) image->height;
1151    req->send_event = (CARD8) send_event;
1152
1153    UnlockDisplay(dpy);
1154    SyncHandle();
1155
1156    return Success;
1157}
1158
1159
1160static Bool
1161xv_wire_to_event(Display *dpy, XEvent *host, xEvent *wire)
1162{
1163    XExtDisplayInfo *info = xv_find_display(dpy);
1164    XvEvent *re = (XvEvent *) host;
1165    xvEvent *event = (xvEvent *) wire;
1166
1167    XvCheckExtension(dpy, info, False);
1168
1169    switch ((event->u.u.type & 0x7F) - info->codes->first_event) {
1170    case XvVideoNotify:
1171        re->xvvideo.type = event->u.u.type & 0x7f;
1172        re->xvvideo.serial = _XSetLastRequestRead(dpy, (xGenericReply *) event);
1173        re->xvvideo.send_event = ((event->u.u.type & 0x80) != 0);
1174        re->xvvideo.display = dpy;
1175        re->xvvideo.time = event->u.videoNotify.time;
1176        re->xvvideo.reason = event->u.videoNotify.reason;
1177        re->xvvideo.drawable = event->u.videoNotify.drawable;
1178        re->xvvideo.port_id = event->u.videoNotify.port;
1179        break;
1180    case XvPortNotify:
1181        re->xvport.type = event->u.u.type & 0x7f;
1182        re->xvport.serial = _XSetLastRequestRead(dpy, (xGenericReply *) event);
1183        re->xvport.send_event = ((event->u.u.type & 0x80) != 0);
1184        re->xvport.display = dpy;
1185        re->xvport.time = event->u.portNotify.time;
1186        re->xvport.port_id = event->u.portNotify.port;
1187        re->xvport.attribute = event->u.portNotify.attribute;
1188        re->xvport.value = event->u.portNotify.value;
1189        break;
1190    default:
1191        return False;
1192    }
1193
1194    return (True);
1195}
1196