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