Xv.c revision dc088bc7
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    else if (rep.num_adaptors != 0) {
196        status = XvBadReply;
197        goto out;
198    }
199
200    /* GET INPUT ADAPTORS */
201
202    if (rep.num_adaptors == 0) {
203        /* If there are no adaptors, there's nothing more to do. */
204        status = Success;
205        goto out;
206    }
207
208    u.buffer = buffer;
209    end = buffer + size;
210
211    if ((pas = Xcalloc(rep.num_adaptors, sizeof(XvAdaptorInfo))) == NULL) {
212        status = XvBadAlloc;
213        goto out;
214    }
215
216    /* INIT ADAPTOR FIELDS */
217
218    pa = pas;
219    for (unsigned int ii = 0; ii < rep.num_adaptors; ii++) {
220        char *name;
221
222        if (u.buffer + sz_xvAdaptorInfo > end) {
223            status = XvBadReply;
224            goto out;
225        }
226        pa->type = (char) u.pa->type;
227        pa->base_id = u.pa->base_id;
228        pa->num_ports = u.pa->num_ports;
229        pa->num_formats = u.pa->num_formats;
230        pa->num_adaptors = rep.num_adaptors - ii;
231
232        /* GET ADAPTOR NAME */
233
234        size = u.pa->name_size;
235        u.buffer += pad_to_int32(sz_xvAdaptorInfo);
236
237        if (u.buffer + size > end) {
238            status = XvBadReply;
239            goto out;
240        }
241        if ((name = Xmalloc(size + 1)) == NULL) {
242            status = XvBadAlloc;
243            goto out;
244        }
245        (void) strncpy(name, u.string, size);
246        name[size] = '\0';
247        pa->name = name;
248
249        u.buffer += pad_to_int32(size);
250
251        /* GET FORMATS */
252
253        if ((pfs = Xcalloc(pa->num_formats, sizeof(XvFormat))) == NULL) {
254            status = XvBadAlloc;
255            goto out;
256        }
257
258        pf = pfs;
259        for (unsigned int jj = 0; jj < pa->num_formats; jj++) {
260            if (u.buffer + sz_xvFormat > end) {
261                Xfree(pfs);
262                status = XvBadReply;
263                goto out;
264            }
265            pf->depth = (char) u.pf->depth;
266            pf->visual_id = u.pf->visual;
267            pf++;
268
269            u.buffer += pad_to_int32(sz_xvFormat);
270        }
271
272        pa->formats = pfs;
273
274        pa++;
275
276    }
277
278    status = Success;
279
280  out:
281    if (status != Success) {
282        XvFreeAdaptorInfo(pas);
283        pas = NULL;
284    }
285
286    *p_nAdaptors = rep.num_adaptors;
287    *p_pAdaptors = pas;
288
289    Xfree(buffer);
290    UnlockDisplay(dpy);
291    SyncHandle();
292
293    return status;
294}
295
296
297void
298XvFreeAdaptorInfo(XvAdaptorInfo *pAdaptors)
299{
300    XvAdaptorInfo *pa;
301
302    if (!pAdaptors)
303        return;
304
305    pa = pAdaptors;
306
307    for (unsigned int ii = 0; ii < pAdaptors->num_adaptors; ii++, pa++) {
308        if (pa->name) {
309            Xfree(pa->name);
310        }
311        if (pa->formats) {
312            Xfree(pa->formats);
313        }
314    }
315
316    Xfree(pAdaptors);
317}
318
319int
320XvQueryEncodings(
321    Display *dpy,
322    XvPortID port,
323    unsigned int *p_nEncodings,
324    XvEncodingInfo ** p_pEncodings)
325{
326    XExtDisplayInfo *info = xv_find_display(dpy);
327    xvQueryEncodingsReq *req;
328    xvQueryEncodingsReply rep;
329    size_t size;
330    XvEncodingInfo *pes = NULL, *pe;
331    char *buffer = NULL;
332    char *end;
333    union {
334        char *buffer;
335        char *string;
336        xvEncodingInfo *pe;
337    } u;
338    int status;
339
340    XvCheckExtension(dpy, info, XvBadExtension);
341
342    LockDisplay(dpy);
343
344    XvGetReq(QueryEncodings, req);
345    req->port = (CARD32) port;
346
347    /* READ THE REPLY */
348
349    if (_XReply(dpy, (xReply *) &rep, 0, xFalse) == 0) {
350        rep.num_encodings = 0;
351        status = XvBadReply;
352        goto out;
353    }
354
355    size = rep.length << 2;
356    if (size > 0) {
357        if ((buffer = Xmalloc(size)) == NULL) {
358            _XEatDataWords(dpy, rep.length);
359            status = XvBadAlloc;
360            goto out;
361        }
362        _XRead(dpy, buffer, (long) size);
363    }
364    else if (rep.num_encodings != 0) {
365        status = XvBadReply;
366        goto out;
367    }
368
369    /* GET ENCODINGS */
370
371    if (rep.num_encodings == 0) {
372        /* If there are no encodings, there's nothing more to do. */
373        status = Success;
374        goto out;
375    }
376
377    u.buffer = buffer;
378    end = buffer + size;
379
380    if ((pes = Xcalloc(rep.num_encodings, sizeof(XvEncodingInfo))) == NULL) {
381        status = XvBadAlloc;
382        goto out;
383    }
384
385    /* INITIALIZE THE ENCODING POINTER */
386
387    pe = pes;
388    for (unsigned int jj = 0; jj < rep.num_encodings; jj++) {
389        char *name;
390
391        if (u.buffer + sz_xvEncodingInfo > end) {
392            status = XvBadReply;
393            goto out;
394        }
395        pe->encoding_id = u.pe->encoding;
396        pe->width = u.pe->width;
397        pe->height = u.pe->height;
398        pe->rate.numerator = u.pe->rate.numerator;
399        pe->rate.denominator = u.pe->rate.denominator;
400        pe->num_encodings = rep.num_encodings - jj;
401
402        size = u.pe->name_size;
403        u.buffer += pad_to_int32(sz_xvEncodingInfo);
404
405        if (u.buffer + size > end) {
406            status = XvBadReply;
407            goto out;
408        }
409        if ((name = Xmalloc(size + 1)) == NULL) {
410            status = XvBadAlloc;
411            goto out;
412        }
413        strncpy(name, u.string, size);
414        name[size] = '\0';
415        pe->name = name;
416        pe++;
417
418        u.buffer += pad_to_int32(size);
419    }
420
421    status = Success;
422
423  out:
424    if (status != Success) {
425        XvFreeEncodingInfo(pes);
426        pes = NULL;
427    }
428
429    *p_nEncodings = rep.num_encodings;
430    *p_pEncodings = pes;
431
432    Xfree(buffer);
433    UnlockDisplay(dpy);
434    SyncHandle();
435
436    return (Success);
437}
438
439void
440XvFreeEncodingInfo(XvEncodingInfo *pEncodings)
441{
442    XvEncodingInfo *pe;
443
444    if (!pEncodings)
445        return;
446
447    pe = pEncodings;
448
449    for (unsigned long ii = 0; ii < pEncodings->num_encodings; ii++, pe++) {
450        if (pe->name)
451            Xfree(pe->name);
452    }
453
454    Xfree(pEncodings);
455}
456
457int
458XvPutVideo(
459    Display *dpy,
460    XvPortID port,
461    Drawable d,
462    GC gc,
463    int vx, int vy,
464    unsigned int vw, unsigned int vh,
465    int dx, int dy,
466    unsigned int dw, unsigned int dh)
467{
468    XExtDisplayInfo *info = xv_find_display(dpy);
469    xvPutVideoReq *req;
470
471    XvCheckExtension(dpy, info, XvBadExtension);
472
473    LockDisplay(dpy);
474
475    FlushGC(dpy, gc);
476
477    XvGetReq(PutVideo, req);
478
479    req->port = (CARD32) port;
480    req->drawable = (CARD32) d;
481    req->gc = (CARD32) gc->gid;
482    req->vid_x = (INT16) vx;
483    req->vid_y = (INT16) vy;
484    req->vid_w = (CARD16) vw;
485    req->vid_h = (CARD16) vh;
486    req->drw_x = (INT16) dx;
487    req->drw_y = (INT16) dy;
488    req->drw_w = (CARD16) dw;
489    req->drw_h = (CARD16) dh;
490
491    UnlockDisplay(dpy);
492    SyncHandle();
493
494    return Success;
495}
496
497int
498XvPutStill(
499    Display *dpy,
500    XvPortID port,
501    Drawable d,
502    GC gc,
503    int vx, int vy,
504    unsigned int vw, unsigned int vh,
505    int dx, int dy,
506    unsigned int dw, unsigned int dh)
507{
508    XExtDisplayInfo *info = xv_find_display(dpy);
509    xvPutStillReq *req;
510
511    XvCheckExtension(dpy, info, XvBadExtension);
512
513    LockDisplay(dpy);
514
515    FlushGC(dpy, gc);
516
517    XvGetReq(PutStill, req);
518    req->port = (CARD32) port;
519    req->drawable = (CARD32) d;
520    req->gc = (CARD32) gc->gid;
521    req->vid_x = (INT16) vx;
522    req->vid_y = (INT16) vy;
523    req->vid_w = (CARD16) vw;
524    req->vid_h = (CARD16) vh;
525    req->drw_x = (INT16) dx;
526    req->drw_y = (INT16) dy;
527    req->drw_w = (CARD16) dw;
528    req->drw_h = (CARD16) dh;
529
530    UnlockDisplay(dpy);
531    SyncHandle();
532
533    return Success;
534}
535
536int
537XvGetVideo(
538    Display *dpy,
539    XvPortID port,
540    Drawable d,
541    GC gc,
542    int vx, int vy,
543    unsigned int vw, unsigned int vh,
544    int dx, int dy,
545    unsigned int dw, unsigned int dh)
546{
547    XExtDisplayInfo *info = xv_find_display(dpy);
548    xvGetVideoReq *req;
549
550    XvCheckExtension(dpy, info, XvBadExtension);
551
552    LockDisplay(dpy);
553
554    FlushGC(dpy, gc);
555
556    XvGetReq(GetVideo, req);
557    req->port = (CARD32) port;
558    req->drawable = (CARD32) d;
559    req->gc = (CARD32) gc->gid;
560    req->vid_x = (INT16) vx;
561    req->vid_y = (INT16) vy;
562    req->vid_w = (CARD16) vw;
563    req->vid_h = (CARD16) vh;
564    req->drw_x = (INT16) dx;
565    req->drw_y = (INT16) dy;
566    req->drw_w = (CARD16) dw;
567    req->drw_h = (CARD16) dh;
568
569    UnlockDisplay(dpy);
570    SyncHandle();
571
572    return Success;
573}
574
575int
576XvGetStill(
577    Display *dpy,
578    XvPortID port,
579    Drawable d,
580    GC gc,
581    int vx, int vy,
582    unsigned int vw, unsigned int vh,
583    int dx, int dy,
584    unsigned int dw, unsigned int dh)
585{
586    XExtDisplayInfo *info = xv_find_display(dpy);
587    xvGetStillReq *req;
588
589    XvCheckExtension(dpy, info, XvBadExtension);
590
591    LockDisplay(dpy);
592
593    FlushGC(dpy, gc);
594
595    XvGetReq(GetStill, req);
596    req->port = (CARD32) port;
597    req->drawable = (CARD32) d;
598    req->gc = (CARD32) gc->gid;
599    req->vid_x = (INT16) vx;
600    req->vid_y = (INT16) vy;
601    req->vid_w = (CARD16) vw;
602    req->vid_h = (CARD16) vh;
603    req->drw_x = (INT16) dx;
604    req->drw_y = (INT16) dy;
605    req->drw_w = (CARD16) dw;
606    req->drw_h = (CARD16) dh;
607
608    UnlockDisplay(dpy);
609    SyncHandle();
610
611    return Success;
612}
613
614int
615XvStopVideo(Display *dpy, XvPortID port, Drawable draw)
616{
617    XExtDisplayInfo *info = xv_find_display(dpy);
618    xvStopVideoReq *req;
619
620    XvCheckExtension(dpy, info, XvBadExtension);
621
622    LockDisplay(dpy);
623
624    XvGetReq(StopVideo, req);
625    req->port = (CARD32) port;
626    req->drawable = (CARD32) draw;
627
628    UnlockDisplay(dpy);
629    SyncHandle();
630
631    return Success;
632}
633
634int
635XvGrabPort(Display *dpy, XvPortID port, Time time)
636{
637    XExtDisplayInfo *info = xv_find_display(dpy);
638    int result;
639    xvGrabPortReply rep;
640    xvGrabPortReq *req;
641
642    XvCheckExtension(dpy, info, XvBadExtension);
643
644    LockDisplay(dpy);
645
646    XvGetReq(GrabPort, req);
647    req->port = (CARD32) port;
648    req->time = (CARD32) time;
649
650    if (_XReply(dpy, (xReply *) &rep, 0, xTrue) == 0)
651        rep.result = GrabSuccess;
652
653    result = rep.result;
654
655    UnlockDisplay(dpy);
656    SyncHandle();
657
658    return result;
659}
660
661int
662XvUngrabPort(Display *dpy, XvPortID port, Time time)
663{
664    XExtDisplayInfo *info = xv_find_display(dpy);
665    xvUngrabPortReq *req;
666
667    XvCheckExtension(dpy, info, XvBadExtension);
668
669    LockDisplay(dpy);
670
671    XvGetReq(UngrabPort, req);
672    req->port = (CARD32) port;
673    req->time = (CARD32) time;
674
675    UnlockDisplay(dpy);
676    SyncHandle();
677
678    return Success;
679}
680
681int
682XvSelectVideoNotify(Display *dpy, Drawable drawable, Bool onoff)
683{
684    XExtDisplayInfo *info = xv_find_display(dpy);
685    xvSelectVideoNotifyReq *req;
686
687    XvCheckExtension(dpy, info, XvBadExtension);
688
689    LockDisplay(dpy);
690
691    XvGetReq(SelectVideoNotify, req);
692    req->drawable = (CARD32) drawable;
693    req->onoff = (BOOL) onoff;
694
695    UnlockDisplay(dpy);
696    SyncHandle();
697
698    return Success;
699}
700
701int
702XvSelectPortNotify(Display *dpy, XvPortID port, Bool onoff)
703{
704    XExtDisplayInfo *info = xv_find_display(dpy);
705    xvSelectPortNotifyReq *req;
706
707    XvCheckExtension(dpy, info, XvBadExtension);
708
709    LockDisplay(dpy);
710
711    XvGetReq(SelectPortNotify, req);
712    req->port = (CARD32) port;
713    req->onoff = (BOOL) onoff;
714
715    UnlockDisplay(dpy);
716    SyncHandle();
717
718    return Success;
719}
720
721int
722XvSetPortAttribute(Display *dpy, XvPortID port, Atom attribute, int value)
723{
724    XExtDisplayInfo *info = xv_find_display(dpy);
725    xvSetPortAttributeReq *req;
726
727    XvCheckExtension(dpy, info, XvBadExtension);
728
729    LockDisplay(dpy);
730
731    XvGetReq(SetPortAttribute, req);
732    req->port = (CARD32) port;
733    req->attribute = (CARD32) attribute;
734    req->value = value;
735
736    UnlockDisplay(dpy);
737    SyncHandle();
738
739    return (Success);
740}
741
742int
743XvGetPortAttribute(Display *dpy, XvPortID port, Atom attribute, int *p_value)
744{
745    XExtDisplayInfo *info = xv_find_display(dpy);
746    xvGetPortAttributeReq *req;
747    xvGetPortAttributeReply rep;
748    int status;
749
750    XvCheckExtension(dpy, info, XvBadExtension);
751
752    LockDisplay(dpy);
753
754    XvGetReq(GetPortAttribute, req);
755    req->port = (CARD32) port;
756    req->attribute = (CARD32) attribute;
757
758    /* READ THE REPLY */
759
760    if (_XReply(dpy, (xReply *) &rep, 0, xFalse) == 0) {
761        status = XvBadReply;
762    }
763    else {
764        *p_value = rep.value;
765        status = Success;
766    }
767
768    UnlockDisplay(dpy);
769    SyncHandle();
770
771    return status;
772}
773
774int
775XvQueryBestSize(
776    Display *dpy,
777    XvPortID port,
778    Bool motion,
779    unsigned int vid_w,
780    unsigned int vid_h,
781    unsigned int drw_w,
782    unsigned int drw_h,
783    unsigned int *p_actual_width,
784    unsigned int *p_actual_height)
785{
786    XExtDisplayInfo *info = xv_find_display(dpy);
787    xvQueryBestSizeReq *req;
788    xvQueryBestSizeReply rep;
789    int status;
790
791    XvCheckExtension(dpy, info, XvBadExtension);
792
793    LockDisplay(dpy);
794
795    XvGetReq(QueryBestSize, req);
796    req->port = (CARD32) port;
797    req->motion = (CARD8) motion;
798    req->vid_w = (CARD16) vid_w;
799    req->vid_h = (CARD16) vid_h;
800    req->drw_w = (CARD16) drw_w;
801    req->drw_h = (CARD16) drw_h;
802
803    /* READ THE REPLY */
804
805    if (_XReply(dpy, (xReply *) &rep, 0, xFalse) == 0) {
806        status = XvBadReply;
807    }
808    else {
809        *p_actual_width = rep.actual_width;
810        *p_actual_height = rep.actual_height;
811        status = Success;
812    }
813
814    UnlockDisplay(dpy);
815    SyncHandle();
816
817    return status;
818}
819
820
821XvAttribute *
822XvQueryPortAttributes(Display *dpy, XvPortID port, int *num)
823{
824    XExtDisplayInfo *info = xv_find_display(dpy);
825    xvQueryPortAttributesReq *req;
826    xvQueryPortAttributesReply rep;
827    XvAttribute *ret = NULL;
828
829    *num = 0;
830
831    XvCheckExtension(dpy, info, NULL);
832
833    LockDisplay(dpy);
834
835    XvGetReq(QueryPortAttributes, req);
836    req->port = (CARD32) port;
837
838    /* READ THE REPLY */
839
840    if (_XReply(dpy, (xReply *) &rep, 0, xFalse) == 0) {
841        goto out;
842    }
843
844    /*
845     * X server sends data packed as:
846     *   attribute1, name1, attribute2, name2, ...
847     * We allocate a single buffer large enough to hold them all and
848     * then de-interleave the data so we return it to clients as:
849     *   attribute1, attribute2, ..., name1, name2, ...
850     * so that clients may refer to attributes as a simple array of
851     * structs:  attributes[0], attributes[1], ...
852     * and free it as a single/simple buffer.
853     */
854
855    if (rep.num_attributes) {
856        /* limit each part to no more than one half the max size */
857        if ((rep.num_attributes < ((INT_MAX / 2) / sizeof(XvAttribute))) &&
858            (rep.text_size < (INT_MAX / 2) - 1)) {
859            unsigned long size;
860
861            size = (rep.num_attributes * sizeof(XvAttribute)) +
862		rep.text_size + 1;
863            ret = Xmalloc(size);
864        }
865
866        if (ret != NULL) {
867            char *marker = (char *) (&ret[rep.num_attributes]);
868            xvAttributeInfo Info;
869
870            /* keep track of remaining room for text strings */
871            unsigned long size = rep.text_size;
872
873            for (unsigned int i = 0; i < rep.num_attributes; i++) {
874                _XRead(dpy, (char *) (&Info), sz_xvAttributeInfo);
875                ret[i].flags = (int) Info.flags;
876                ret[i].min_value = Info.min;
877                ret[i].max_value = Info.max;
878                ret[i].name = marker;
879                if (Info.size <= size) {
880                    _XRead(dpy, marker, Info.size);
881                    marker += Info.size;
882                    size -= Info.size;
883                }
884                (*num)++;
885            }
886
887            /* ensure final string is nil-terminated to avoid exposure of
888               uninitialized memory */
889            *marker = '\0';
890        }
891        else
892            _XEatDataWords(dpy, rep.length);
893    }
894
895  out:
896    UnlockDisplay(dpy);
897    SyncHandle();
898
899    return ret;
900}
901
902XvImageFormatValues *
903XvListImageFormats(Display *dpy, XvPortID port, int *num)
904{
905    XExtDisplayInfo *info = xv_find_display(dpy);
906    xvListImageFormatsReq *req;
907    xvListImageFormatsReply rep;
908    XvImageFormatValues *ret = NULL;
909
910    *num = 0;
911
912    XvCheckExtension(dpy, info, NULL);
913
914    LockDisplay(dpy);
915
916    XvGetReq(ListImageFormats, req);
917    req->port = (CARD32) port;
918
919    /* READ THE REPLY */
920
921    if (_XReply(dpy, (xReply *) &rep, 0, xFalse) == 0) {
922        goto out;
923    }
924
925    if (rep.num_formats) {
926        if (rep.num_formats < (INT_MAX / sizeof(XvImageFormatValues)))
927            ret = Xcalloc(rep.num_formats, sizeof(XvImageFormatValues));
928
929        if (ret != NULL) {
930            for (unsigned int i = 0; i < rep.num_formats; i++) {
931                xvImageFormatInfo Info;
932
933                _XRead(dpy, (char *) (&Info), sz_xvImageFormatInfo);
934                ret[i].id = (int) Info.id;
935                ret[i].type = Info.type;
936                ret[i].byte_order = Info.byte_order;
937                memcpy(&(ret[i].guid[0]), &(Info.guid[0]), 16);
938                ret[i].bits_per_pixel = Info.bpp;
939                ret[i].format = Info.format;
940                ret[i].num_planes = Info.num_planes;
941                ret[i].depth = Info.depth;
942                ret[i].red_mask = Info.red_mask;
943                ret[i].green_mask = Info.green_mask;
944                ret[i].blue_mask = Info.blue_mask;
945                ret[i].y_sample_bits = Info.y_sample_bits;
946                ret[i].u_sample_bits = Info.u_sample_bits;
947                ret[i].v_sample_bits = Info.v_sample_bits;
948                ret[i].horz_y_period = Info.horz_y_period;
949                ret[i].horz_u_period = Info.horz_u_period;
950                ret[i].horz_v_period = Info.horz_v_period;
951                ret[i].vert_y_period = Info.vert_y_period;
952                ret[i].vert_u_period = Info.vert_u_period;
953                ret[i].vert_v_period = Info.vert_v_period;
954                memcpy(&(ret[i].component_order[0]), &(Info.comp_order[0]), 32);
955                ret[i].scanline_order = Info.scanline_order;
956                (*num)++;
957            }
958        }
959        else
960            _XEatDataWords(dpy, rep.length);
961    }
962
963  out:
964    UnlockDisplay(dpy);
965    SyncHandle();
966
967    return ret;
968}
969
970XvImage *
971XvCreateImage(
972    Display *dpy,
973    XvPortID port,
974    int id,
975    char *data,
976    int width,
977    int height)
978{
979    XExtDisplayInfo *info = xv_find_display(dpy);
980    xvQueryImageAttributesReq *req;
981    xvQueryImageAttributesReply rep;
982    XvImage *ret = NULL;
983
984    XvCheckExtension(dpy, info, NULL);
985
986    LockDisplay(dpy);
987
988    XvGetReq(QueryImageAttributes, req);
989    req->id = (CARD32) id;
990    req->port = (CARD32) port;
991    req->width = (CARD16) width;
992    req->height = (CARD16) height;
993
994    /* READ THE REPLY */
995
996    if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
997        goto out;
998    }
999
1000    if (rep.num_planes < ((INT_MAX >> 3) - sizeof(XvImage)))
1001        ret = Xmalloc(sizeof(XvImage) + (rep.num_planes << 3));
1002
1003    if (ret != NULL) {
1004        ret->id = id;
1005        ret->width = rep.width;
1006        ret->height = rep.height;
1007        ret->data_size = (int) rep.data_size;
1008        ret->num_planes = (int) rep.num_planes;
1009        ret->pitches = (int *) (&ret[1]);
1010        ret->offsets = ret->pitches + rep.num_planes;
1011        ret->data = data;
1012        ret->obdata = NULL;
1013        _XRead(dpy, (char *) (ret->pitches), rep.num_planes << 2);
1014        _XRead(dpy, (char *) (ret->offsets), rep.num_planes << 2);
1015    }
1016    else
1017        _XEatDataWords(dpy, rep.length);
1018
1019  out:
1020    UnlockDisplay(dpy);
1021    SyncHandle();
1022
1023    return ret;
1024}
1025
1026XvImage *
1027XvShmCreateImage(
1028    Display *dpy,
1029    XvPortID port,
1030    int id,
1031    char *data,
1032    int width,
1033    int height,
1034    XShmSegmentInfo *shminfo)
1035{
1036    XvImage *ret;
1037
1038    ret = XvCreateImage(dpy, port, id, data, width, height);
1039
1040    if (ret)
1041        ret->obdata = (XPointer) shminfo;
1042
1043    return ret;
1044}
1045
1046int
1047XvPutImage(
1048    Display *dpy,
1049    XvPortID port,
1050    Drawable d,
1051    GC gc,
1052    XvImage *image,
1053    int src_x, int src_y,
1054    unsigned int src_w, unsigned int src_h,
1055    int dest_x, int dest_y,
1056    unsigned int dest_w, unsigned int dest_h)
1057{
1058    XExtDisplayInfo *info = xv_find_display(dpy);
1059    xvPutImageReq *req;
1060    unsigned int len;
1061
1062    XvCheckExtension(dpy, info, XvBadExtension);
1063
1064    LockDisplay(dpy);
1065
1066    FlushGC(dpy, gc);
1067
1068    XvGetReq(PutImage, req);
1069
1070    req->port = (CARD32) port;
1071    req->drawable = (CARD32) d;
1072    req->gc = (CARD32) gc->gid;
1073    req->id = (CARD32) image->id;
1074    req->src_x = (INT16) src_x;
1075    req->src_y = (INT16) src_y;
1076    req->src_w = (CARD16) src_w;
1077    req->src_h = (CARD16) src_h;
1078    req->drw_x = (INT16) dest_x;
1079    req->drw_y = (INT16) dest_y;
1080    req->drw_w = (CARD16) dest_w;
1081    req->drw_h = (CARD16) dest_h;
1082    req->width = (CARD16) image->width;
1083    req->height = (CARD16) image->height;
1084
1085    len = ((unsigned int) image->data_size + 3) >> 2;
1086    SetReqLen(req, len, len);
1087
1088    /* Yes it's kindof lame that we are sending the whole thing,
1089       but for video all of it may be needed even if displaying
1090       only a subsection, and I don't want to go through the
1091       trouble of creating subregions to send */
1092    Data(dpy, (char *) image->data, image->data_size);
1093
1094    UnlockDisplay(dpy);
1095    SyncHandle();
1096
1097    return Success;
1098}
1099
1100int
1101XvShmPutImage(
1102    Display *dpy,
1103    XvPortID port,
1104    Drawable d,
1105    GC gc,
1106    XvImage *image,
1107    int src_x, int src_y,
1108    unsigned int src_w, unsigned int src_h,
1109    int dest_x, int dest_y,
1110    unsigned int dest_w, unsigned int dest_h,
1111    Bool send_event)
1112{
1113    XExtDisplayInfo *info = xv_find_display(dpy);
1114    XShmSegmentInfo *shminfo = (XShmSegmentInfo *) image->obdata;
1115    xvShmPutImageReq *req;
1116
1117    XvCheckExtension(dpy, info, XvBadExtension);
1118
1119    LockDisplay(dpy);
1120
1121    FlushGC(dpy, gc);
1122
1123    XvGetReq(ShmPutImage, req);
1124
1125    req->port = (CARD32) port;
1126    req->drawable = (CARD32) d;
1127    req->gc = (CARD32) gc->gid;
1128    req->shmseg = (CARD32) shminfo->shmseg;
1129    req->id = (CARD32) image->id;
1130    req->src_x = (INT16) src_x;
1131    req->src_y = (INT16) src_y;
1132    req->src_w = (CARD16) src_w;
1133    req->src_h = (CARD16) src_h;
1134    req->drw_x = (INT16) dest_x;
1135    req->drw_y = (INT16) dest_y;
1136    req->drw_w = (CARD16) dest_w;
1137    req->drw_h = (CARD16) dest_h;
1138    req->offset = (CARD32) (image->data - shminfo->shmaddr);
1139    req->width = (CARD16) image->width;
1140    req->height = (CARD16) image->height;
1141    req->send_event = (CARD8) send_event;
1142
1143    UnlockDisplay(dpy);
1144    SyncHandle();
1145
1146    return Success;
1147}
1148
1149
1150static Bool
1151xv_wire_to_event(Display *dpy, XEvent *host, xEvent *wire)
1152{
1153    XExtDisplayInfo *info = xv_find_display(dpy);
1154    XvEvent *re = (XvEvent *) host;
1155    xvEvent *event = (xvEvent *) wire;
1156
1157    XvCheckExtension(dpy, info, False);
1158
1159    switch ((event->u.u.type & 0x7F) - info->codes->first_event) {
1160    case XvVideoNotify:
1161        re->xvvideo.type = event->u.u.type & 0x7f;
1162        re->xvvideo.serial = _XSetLastRequestRead(dpy, (xGenericReply *) event);
1163        re->xvvideo.send_event = ((event->u.u.type & 0x80) != 0);
1164        re->xvvideo.display = dpy;
1165        re->xvvideo.time = event->u.videoNotify.time;
1166        re->xvvideo.reason = event->u.videoNotify.reason;
1167        re->xvvideo.drawable = event->u.videoNotify.drawable;
1168        re->xvvideo.port_id = event->u.videoNotify.port;
1169        break;
1170    case XvPortNotify:
1171        re->xvport.type = event->u.u.type & 0x7f;
1172        re->xvport.serial = _XSetLastRequestRead(dpy, (xGenericReply *) event);
1173        re->xvport.send_event = ((event->u.u.type & 0x80) != 0);
1174        re->xvport.display = dpy;
1175        re->xvport.time = event->u.portNotify.time;
1176        re->xvport.port_id = event->u.portNotify.port;
1177        re->xvport.attribute = event->u.portNotify.attribute;
1178        re->xvport.value = event->u.portNotify.value;
1179        break;
1180    default:
1181        return False;
1182    }
1183
1184    return (True);
1185}
1186