1 /***********************************************************
2 Copyright 1991 by Digital Equipment Corporation, Maynard, Massachusetts,
3 and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Digital or MIT not be
12 used in advertising or publicity pertaining to distribution of the
13 software without specific, written prior permission.
15 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
16 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
17 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
18 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
20 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
23 ******************************************************************/
27 ** Xv.c --- Xv library extension module.
31 ** David Carver (Digital Workstation Engineering/Project Athena)
36 ** - changed XvFreeAdaptors to XvFreeAdaptorInfo
37 ** - changed XvFreeEncodings to XvFreeEncodingInfo
40 ** - changed SetPortControl to SetPortAttribute
41 ** - changed GetPortControl to GetPortAttribute
42 ** - changed QueryBestSize
45 ** - version 2.0 upgrade
48 ** - version 1.4 upgrade
58 #include <X11/extensions/Xext.h>
59 #include <X11/extensions/extutil.h>
60 #include <X11/extensions/XShm.h>
63 static XExtensionInfo _xv_info_data;
64 static XExtensionInfo *xv_info = &_xv_info_data;
65 static const char *xv_extension_name = XvName;
67 #define XvCheckExtension(dpy, i, val) \
68 XextCheckExtension(dpy, i, xv_extension_name, val)
70 #define pad_to_int32(bytes) (((bytes) + 3) & ~3U)
72 static char *xv_error_string(Display *dpy, int code, XExtCodes *codes,
74 static int xv_close_display(Display *dpy, XExtCodes *codes);
75 static Bool xv_wire_to_event(Display *dpy, XEvent *host, xEvent *wire);
77 static XExtensionHooks xv_extension_hooks = {
82 NULL, /* create_font */
84 xv_close_display, /* close_display */
85 xv_wire_to_event, /* wire_to_event */
86 NULL, /* event_to_wire */
88 xv_error_string /* error_string */
92 static const char *xv_error_list[] = {
93 "BadPort", /* XvBadPort */
94 "BadEncoding", /* XvBadEncoding */
95 "BadControl" /* XvBadControl */
98 static XEXT_GENERATE_CLOSE_DISPLAY(xv_close_display, xv_info)
100 static XEXT_GENERATE_FIND_DISPLAY(xv_find_display, xv_info,
101 xv_extension_name, &xv_extension_hooks,
104 static XEXT_GENERATE_ERROR_STRING(xv_error_string, xv_extension_name,
105 XvNumErrors, xv_error_list)
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)
117 XExtDisplayInfo *info = xv_find_display(dpy);
118 xvQueryExtensionReq *req;
119 xvQueryExtensionReply rep;
122 XvCheckExtension(dpy, info, XvBadExtension);
126 XvGetReq(QueryExtension, req);
128 if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
129 status = XvBadExtension;
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;
152 unsigned int *p_nAdaptors,
153 XvAdaptorInfo **p_pAdaptors)
155 XExtDisplayInfo *info = xv_find_display(dpy);
156 xvQueryAdaptorsReq *req;
157 xvQueryAdaptorsReply rep;
161 XvAdaptorInfo *pas = NULL, *pa;
172 XvCheckExtension(dpy, info, XvBadExtension);
176 XvGetReq(QueryAdaptors, req);
177 req->window = window;
181 if (_XReply(dpy, (xReply *) &rep, 0, xFalse) == 0) {
182 rep.num_adaptors = 0;
187 size = rep.length << 2;
189 if ((buffer = Xmalloc(size)) == NULL) {
190 _XEatDataWords(dpy, rep.length);
194 _XRead(dpy, buffer, (long) size);
197 /* GET INPUT ADAPTORS */
199 if (rep.num_adaptors == 0) {
200 /* If there's no adaptors, there's nothing more to do. */
205 if (size < (rep.num_adaptors * sz_xvAdaptorInfo)) {
206 /* If there's not enough data for the number of adaptors,
207 then we have a problem. */
212 size = rep.num_adaptors * sizeof(XvAdaptorInfo);
213 if ((pas = Xmalloc(size)) == NULL) {
218 /* INIT ADAPTOR FIELDS */
221 for (ii = 0; ii < rep.num_adaptors; ii++) {
222 pa->num_adaptors = 0;
223 pa->name = (char *) NULL;
224 pa->formats = (XvFormat *) NULL;
230 for (ii = 0; ii < rep.num_adaptors; ii++) {
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;
237 /* GET ADAPTOR NAME */
239 size = u.pa->name_size;
240 u.buffer += pad_to_int32(sz_xvAdaptorInfo);
242 if ((name = Xmalloc(size + 1)) == NULL) {
246 (void) strncpy(name, u.string, size);
250 u.buffer += pad_to_int32(size);
254 size = pa->num_formats * sizeof(XvFormat);
255 if ((pfs = Xmalloc(size)) == NULL) {
261 for (jj = 0; jj < pa->num_formats; jj++) {
262 pf->depth = u.pf->depth;
263 pf->visual_id = u.pf->visual;
266 u.buffer += pad_to_int32(sz_xvFormat);
278 if (status != Success) {
279 XvFreeAdaptorInfo(pas);
283 *p_nAdaptors = rep.num_adaptors;
295 XvFreeAdaptorInfo(XvAdaptorInfo *pAdaptors)
305 for (ii = 0; ii < pAdaptors->num_adaptors; ii++, pa++) {
321 unsigned int *p_nEncodings,
322 XvEncodingInfo ** p_pEncodings)
324 XExtDisplayInfo *info = xv_find_display(dpy);
325 xvQueryEncodingsReq *req;
326 xvQueryEncodingsReply rep;
330 XvEncodingInfo *pes = NULL, *pe;
339 XvCheckExtension(dpy, info, XvBadExtension);
343 XvGetReq(QueryEncodings, req);
348 if (_XReply(dpy, (xReply *) &rep, 0, xFalse) == 0) {
349 rep.num_encodings = 0;
354 size = rep.length << 2;
356 if ((buffer = Xmalloc(size)) == NULL) {
357 _XEatDataWords(dpy, rep.length);
361 _XRead(dpy, buffer, (long) size);
366 if (rep.num_encodings == 0) {
367 /* If there's no encodings, there's nothing more to do. */
372 if (size < (rep.num_encodings * sz_xvEncodingInfo)) {
373 /* If there's not enough data for the number of adaptors,
374 then we have a problem. */
379 size = rep.num_encodings * sizeof(XvEncodingInfo);
380 if ((pes = Xmalloc(size)) == NULL) {
385 /* INITIALIZE THE ENCODING POINTER */
388 for (jj = 0; jj < rep.num_encodings; jj++) {
389 pe->name = (char *) NULL;
390 pe->num_encodings = 0;
397 for (jj = 0; jj < rep.num_encodings; jj++) {
398 pe->encoding_id = u.pe->encoding;
399 pe->width = u.pe->width;
400 pe->height = u.pe->height;
401 pe->rate.numerator = u.pe->rate.numerator;
402 pe->rate.denominator = u.pe->rate.denominator;
403 pe->num_encodings = rep.num_encodings - jj;
405 size = u.pe->name_size;
406 u.buffer += pad_to_int32(sz_xvEncodingInfo);
408 if ((name = Xmalloc(size + 1)) == NULL) {
412 strncpy(name, u.string, size);
417 u.buffer += pad_to_int32(size);
423 if (status != Success) {
424 XvFreeEncodingInfo(pes);
428 *p_nEncodings = rep.num_encodings;
439 XvFreeEncodingInfo(XvEncodingInfo *pEncodings)
449 for (ii = 0; ii < pEncodings->num_encodings; ii++, pe++) {
464 unsigned int vw, unsigned int vh,
466 unsigned int dw, unsigned int dh)
468 XExtDisplayInfo *info = xv_find_display(dpy);
471 XvCheckExtension(dpy, info, XvBadExtension);
477 XvGetReq(PutVideo, req);
504 unsigned int vw, unsigned int vh,
506 unsigned int dw, unsigned int dh)
508 XExtDisplayInfo *info = xv_find_display(dpy);
511 XvCheckExtension(dpy, info, XvBadExtension);
517 XvGetReq(PutStill, req);
543 unsigned int vw, unsigned int vh,
545 unsigned int dw, unsigned int dh)
547 XExtDisplayInfo *info = xv_find_display(dpy);
550 XvCheckExtension(dpy, info, XvBadExtension);
556 XvGetReq(GetVideo, req);
582 unsigned int vw, unsigned int vh,
584 unsigned int dw, unsigned int dh)
586 XExtDisplayInfo *info = xv_find_display(dpy);
589 XvCheckExtension(dpy, info, XvBadExtension);
595 XvGetReq(GetStill, req);
615 XvStopVideo(Display *dpy, XvPortID port, Drawable draw)
617 XExtDisplayInfo *info = xv_find_display(dpy);
620 XvCheckExtension(dpy, info, XvBadExtension);
624 XvGetReq(StopVideo, req);
626 req->drawable = draw;
635 XvGrabPort(Display *dpy, XvPortID port, Time time)
637 XExtDisplayInfo *info = xv_find_display(dpy);
642 XvCheckExtension(dpy, info, XvBadExtension);
646 XvGetReq(GrabPort, req);
650 if (_XReply(dpy, (xReply *) &rep, 0, xTrue) == 0)
651 rep.result = GrabSuccess;
662 XvUngrabPort(Display *dpy, XvPortID port, Time time)
664 XExtDisplayInfo *info = xv_find_display(dpy);
665 xvUngrabPortReq *req;
667 XvCheckExtension(dpy, info, XvBadExtension);
671 XvGetReq(UngrabPort, req);
682 XvSelectVideoNotify(Display *dpy, Drawable drawable, Bool onoff)
684 XExtDisplayInfo *info = xv_find_display(dpy);
685 xvSelectVideoNotifyReq *req;
687 XvCheckExtension(dpy, info, XvBadExtension);
691 XvGetReq(SelectVideoNotify, req);
692 req->drawable = drawable;
702 XvSelectPortNotify(Display *dpy, XvPortID port, Bool onoff)
704 XExtDisplayInfo *info = xv_find_display(dpy);
705 xvSelectPortNotifyReq *req;
707 XvCheckExtension(dpy, info, XvBadExtension);
711 XvGetReq(SelectPortNotify, req);
722 XvSetPortAttribute(Display *dpy, XvPortID port, Atom attribute, int value)
724 XExtDisplayInfo *info = xv_find_display(dpy);
725 xvSetPortAttributeReq *req;
727 XvCheckExtension(dpy, info, XvBadExtension);
731 XvGetReq(SetPortAttribute, req);
733 req->attribute = attribute;
743 XvGetPortAttribute(Display *dpy, XvPortID port, Atom attribute, int *p_value)
745 XExtDisplayInfo *info = xv_find_display(dpy);
746 xvGetPortAttributeReq *req;
747 xvGetPortAttributeReply rep;
750 XvCheckExtension(dpy, info, XvBadExtension);
754 XvGetReq(GetPortAttribute, req);
756 req->attribute = attribute;
760 if (_XReply(dpy, (xReply *) &rep, 0, xFalse) == 0) {
764 *p_value = rep.value;
783 unsigned int *p_actual_width,
784 unsigned int *p_actual_height)
786 XExtDisplayInfo *info = xv_find_display(dpy);
787 xvQueryBestSizeReq *req;
788 xvQueryBestSizeReply rep;
791 XvCheckExtension(dpy, info, XvBadExtension);
795 XvGetReq(QueryBestSize, req);
797 req->motion = motion;
805 if (_XReply(dpy, (xReply *) &rep, 0, xFalse) == 0) {
809 *p_actual_width = rep.actual_width;
810 *p_actual_height = rep.actual_height;
822 XvQueryPortAttributes(Display *dpy, XvPortID port, int *num)
824 XExtDisplayInfo *info = xv_find_display(dpy);
825 xvQueryPortAttributesReq *req;
826 xvQueryPortAttributesReply rep;
827 XvAttribute *ret = NULL;
831 XvCheckExtension(dpy, info, NULL);
835 XvGetReq(QueryPortAttributes, req);
840 if (_XReply(dpy, (xReply *) &rep, 0, xFalse) == 0) {
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.
855 if (rep.num_attributes) {
858 /* limit each part to no more than one half the max size */
859 if ((rep.num_attributes < ((INT_MAX / 2) / sizeof(XvAttribute))) &&
860 (rep.text_size < (INT_MAX / 2) - 1)) {
861 size = (rep.num_attributes * sizeof(XvAttribute)) +
867 char *marker = (char *) (&ret[rep.num_attributes]);
868 xvAttributeInfo Info;
871 /* keep track of remaining room for text strings */
872 size = rep.text_size;
874 for (i = 0; i < rep.num_attributes; i++) {
875 _XRead(dpy, (char *) (&Info), sz_xvAttributeInfo);
876 ret[i].flags = (int) Info.flags;
877 ret[i].min_value = Info.min;
878 ret[i].max_value = Info.max;
879 ret[i].name = marker;
880 if (Info.size <= size) {
881 _XRead(dpy, marker, Info.size);
888 /* ensure final string is nil-terminated to avoid exposure of
889 uninitialized memory */
893 _XEatDataWords(dpy, rep.length);
903 XvImageFormatValues *
904 XvListImageFormats(Display *dpy, XvPortID port, int *num)
906 XExtDisplayInfo *info = xv_find_display(dpy);
907 xvListImageFormatsReq *req;
908 xvListImageFormatsReply rep;
909 XvImageFormatValues *ret = NULL;
913 XvCheckExtension(dpy, info, NULL);
917 XvGetReq(ListImageFormats, req);
922 if (_XReply(dpy, (xReply *) &rep, 0, xFalse) == 0) {
926 if (rep.num_formats) {
927 if (rep.num_formats < (INT_MAX / sizeof(XvImageFormatValues)))
928 ret = Xmalloc(rep.num_formats * sizeof(XvImageFormatValues));
931 xvImageFormatInfo Info;
934 for (i = 0; i < rep.num_formats; i++) {
935 _XRead(dpy, (char *) (&Info), sz_xvImageFormatInfo);
937 ret[i].type = Info.type;
938 ret[i].byte_order = Info.byte_order;
939 memcpy(&(ret[i].guid[0]), &(Info.guid[0]), 16);
940 ret[i].bits_per_pixel = Info.bpp;
941 ret[i].format = Info.format;
942 ret[i].num_planes = Info.num_planes;
943 ret[i].depth = Info.depth;
944 ret[i].red_mask = Info.red_mask;
945 ret[i].green_mask = Info.green_mask;
946 ret[i].blue_mask = Info.blue_mask;
947 ret[i].y_sample_bits = Info.y_sample_bits;
948 ret[i].u_sample_bits = Info.u_sample_bits;
949 ret[i].v_sample_bits = Info.v_sample_bits;
950 ret[i].horz_y_period = Info.horz_y_period;
951 ret[i].horz_u_period = Info.horz_u_period;
952 ret[i].horz_v_period = Info.horz_v_period;
953 ret[i].vert_y_period = Info.vert_y_period;
954 ret[i].vert_u_period = Info.vert_u_period;
955 ret[i].vert_v_period = Info.vert_v_period;
956 memcpy(&(ret[i].component_order[0]), &(Info.comp_order[0]), 32);
957 ret[i].scanline_order = Info.scanline_order;
962 _XEatDataWords(dpy, rep.length);
981 XExtDisplayInfo *info = xv_find_display(dpy);
982 xvQueryImageAttributesReq *req;
983 xvQueryImageAttributesReply rep;
986 XvCheckExtension(dpy, info, NULL);
990 XvGetReq(QueryImageAttributes, req);
994 req->height = height;
998 if (!_XReply(dpy, (xReply *) &rep, 0, xFalse)) {
1002 if (rep.num_planes < ((INT_MAX >> 3) - sizeof(XvImage)))
1003 ret = Xmalloc(sizeof(XvImage) + (rep.num_planes << 3));
1007 ret->width = rep.width;
1008 ret->height = rep.height;
1009 ret->data_size = rep.data_size;
1010 ret->num_planes = rep.num_planes;
1011 ret->pitches = (int *) (&ret[1]);
1012 ret->offsets = ret->pitches + rep.num_planes;
1015 _XRead(dpy, (char *) (ret->pitches), rep.num_planes << 2);
1016 _XRead(dpy, (char *) (ret->offsets), rep.num_planes << 2);
1019 _XEatDataWords(dpy, rep.length);
1036 XShmSegmentInfo *shminfo)
1040 ret = XvCreateImage(dpy, port, id, data, width, height);
1043 ret->obdata = (XPointer) shminfo;
1055 int src_x, int src_y,
1056 unsigned int src_w, unsigned int src_h,
1057 int dest_x, int dest_y,
1058 unsigned int dest_w, unsigned int dest_h)
1060 XExtDisplayInfo *info = xv_find_display(dpy);
1064 XvCheckExtension(dpy, info, XvBadExtension);
1070 XvGetReq(PutImage, req);
1075 req->id = image->id;
1080 req->drw_x = dest_x;
1081 req->drw_y = dest_y;
1082 req->drw_w = dest_w;
1083 req->drw_h = dest_h;
1084 req->width = image->width;
1085 req->height = image->height;
1087 len = ((unsigned int) image->data_size + 3) >> 2;
1088 SetReqLen(req, len, len);
1090 /* Yes it's kindof lame that we are sending the whole thing,
1091 but for video all of it may be needed even if displaying
1092 only a subsection, and I don't want to go through the
1093 trouble of creating subregions to send */
1094 Data(dpy, (char *) image->data, image->data_size);
1109 int src_x, int src_y,
1110 unsigned int src_w, unsigned int src_h,
1111 int dest_x, int dest_y,
1112 unsigned int dest_w, unsigned int dest_h,
1115 XExtDisplayInfo *info = xv_find_display(dpy);
1116 XShmSegmentInfo *shminfo = (XShmSegmentInfo *) image->obdata;
1117 xvShmPutImageReq *req;
1119 XvCheckExtension(dpy, info, XvBadExtension);
1125 XvGetReq(ShmPutImage, req);
1130 req->shmseg = shminfo->shmseg;
1131 req->id = image->id;
1136 req->drw_x = dest_x;
1137 req->drw_y = dest_y;
1138 req->drw_w = dest_w;
1139 req->drw_h = dest_h;
1140 req->offset = image->data - shminfo->shmaddr;
1141 req->width = image->width;
1142 req->height = image->height;
1143 req->send_event = send_event;
1153 xv_wire_to_event(Display *dpy, XEvent *host, xEvent *wire)
1155 XExtDisplayInfo *info = xv_find_display(dpy);
1156 XvEvent *re = (XvEvent *) host;
1157 xvEvent *event = (xvEvent *) wire;
1159 XvCheckExtension(dpy, info, False);
1161 switch ((event->u.u.type & 0x7F) - info->codes->first_event) {
1163 re->xvvideo.type = event->u.u.type & 0x7f;
1164 re->xvvideo.serial = _XSetLastRequestRead(dpy, (xGenericReply *) event);
1165 re->xvvideo.send_event = ((event->u.u.type & 0x80) != 0);
1166 re->xvvideo.display = dpy;
1167 re->xvvideo.time = event->u.videoNotify.time;
1168 re->xvvideo.reason = event->u.videoNotify.reason;
1169 re->xvvideo.drawable = event->u.videoNotify.drawable;
1170 re->xvvideo.port_id = event->u.videoNotify.port;
1173 re->xvport.type = event->u.u.type & 0x7f;
1174 re->xvport.serial = _XSetLastRequestRead(dpy, (xGenericReply *) event);
1175 re->xvport.send_event = ((event->u.u.type & 0x80) != 0);
1176 re->xvport.display = dpy;
1177 re->xvport.time = event->u.portNotify.time;
1178 re->xvport.port_id = event->u.portNotify.port;
1179 re->xvport.attribute = event->u.portNotify.attribute;
1180 re->xvport.value = event->u.portNotify.value;