Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

video_out_x11.c

Go to the documentation of this file.
00001 /*
00002  * video_out_x11.c
00003  * Copyright (C) 2000-2002 Michel Lespinasse <walken@zoy.org>
00004  * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
00005  *
00006  * This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
00007  * See http://libmpeg2.sourceforge.net/ for updates.
00008  *
00009  * mpeg2dec is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * mpeg2dec is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  */
00023 
00024 #include "config.h"
00025 
00026 #ifdef LIBVO_X11
00027 
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <X11/Xlib.h>
00031 #include <X11/Xutil.h>
00032 #include <sys/ipc.h>
00033 #include <sys/shm.h>
00034 #include <X11/extensions/XShm.h>
00035 #include <inttypes.h>
00036 /* since it doesn't seem to be defined on some platforms */
00037 int XShmGetEventBase (Display *);
00038 
00039 #ifdef LIBVO_XV
00040 #include <string.h>     /* strcmp */
00041 #include <X11/extensions/Xvlib.h>
00042 #define FOURCC_YV12 0x32315659
00043 #endif
00044 
00045 #include "video_out.h"
00046 #include "convert.h"
00047 
00048 typedef struct {
00049     void * data;
00050     int wait_completion;
00051     XImage * ximage;
00052 #ifdef LIBVO_XV
00053     XvImage * xvimage;
00054 #endif
00055 } x11_frame_t;
00056 
00057 typedef struct {
00058     vo_instance_t vo;
00059     x11_frame_t frame[3];
00060     int index;
00061     int width;
00062     int height;
00063     Display * display;
00064     Window window;
00065     GC gc;
00066     XVisualInfo vinfo;
00067     XShmSegmentInfo shminfo;
00068     int completion_type;
00069 #ifdef LIBVO_XV
00070     XvPortID port;
00071 #endif
00072 } x11_instance_t;
00073 
00074 static int open_display (x11_instance_t * instance)
00075 {
00076     int major;
00077     int minor;
00078     Bool pixmaps;
00079     XVisualInfo visualTemplate;
00080     XVisualInfo * XvisualInfoTable;
00081     XVisualInfo * XvisualInfo;
00082     int number;
00083     int i;
00084     XSetWindowAttributes attr;
00085     XGCValues gcValues;
00086 
00087     instance->display = XOpenDisplay (NULL);
00088     if (! (instance->display)) {
00089         fprintf (stderr, "Can not open display\n");
00090         return 1;
00091     }
00092 
00093     if ((XShmQueryVersion (instance->display, &major, &minor,
00094                            &pixmaps) == 0) ||
00095         (major < 1) || ((major == 1) && (minor < 1))) {
00096         fprintf (stderr, "No xshm extension\n");
00097         return 1;
00098     }
00099 
00100     instance->completion_type =
00101         XShmGetEventBase (instance->display) + ShmCompletion;
00102 
00103     /* list truecolor visuals for the default screen */
00104 #ifdef __cplusplus
00105     visualTemplate.c_class = TrueColor;
00106 #else
00107     visualTemplate.class = TrueColor;
00108 #endif
00109     visualTemplate.screen = DefaultScreen (instance->display);
00110     XvisualInfoTable = XGetVisualInfo (instance->display,
00111                                        VisualScreenMask | VisualClassMask,
00112                                        &visualTemplate, &number);
00113     if (XvisualInfoTable == NULL) {
00114         fprintf (stderr, "No truecolor visual\n");
00115         return 1;
00116     }
00117 
00118     /* find the visual with the highest depth */
00119     XvisualInfo = XvisualInfoTable;
00120     for (i = 1; i < number; i++)
00121         if (XvisualInfoTable[i].depth > XvisualInfo->depth)
00122             XvisualInfo = XvisualInfoTable + i;
00123 
00124     instance->vinfo = *XvisualInfo;
00125     XFree (XvisualInfoTable);
00126 
00127     attr.background_pixmap = None;
00128     attr.backing_store = NotUseful;
00129     attr.border_pixel = 0;
00130     attr.event_mask = 0;
00131     /* fucking sun blows me - you have to create a colormap there... */
00132     attr.colormap = XCreateColormap (instance->display,
00133                                      RootWindow (instance->display,
00134                                                  instance->vinfo.screen),
00135                                      instance->vinfo.visual, AllocNone);
00136     instance->window =
00137         XCreateWindow (instance->display,
00138                        DefaultRootWindow (instance->display),
00139                        0 /* x */, 0 /* y */, instance->width, instance->height,
00140                        0 /* border_width */, instance->vinfo.depth,
00141                        InputOutput, instance->vinfo.visual,
00142                        (CWBackPixmap | CWBackingStore | CWBorderPixel |
00143                         CWEventMask | CWColormap), &attr);
00144 
00145     instance->gc = XCreateGC (instance->display, instance->window, 0,
00146                               &gcValues);
00147 
00148     return 0;
00149 }
00150 
00151 static int shmerror = 0;
00152 
00153 static int handle_error (Display * display, XErrorEvent * error)
00154 {
00155     shmerror = 1;
00156     return 0;
00157 }
00158 
00159 static void * create_shm (x11_instance_t * instance, int size)
00160 {
00161     instance->shminfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
00162     if (instance->shminfo.shmid == -1)
00163         goto error;
00164 
00165     instance->shminfo.shmaddr = (char *) shmat (instance->shminfo.shmid, 0, 0);
00166     if (instance->shminfo.shmaddr == (char *)-1)
00167         goto error;
00168 
00169     /* on linux the IPC_RMID only kicks off once everyone detaches the shm */
00170     /* doing this early avoids shm leaks when we are interrupted. */
00171     /* this would break the solaris port though :-/ */
00172     /* shmctl (instance->shminfo.shmid, IPC_RMID, 0); */
00173 
00174     /* XShmAttach fails on remote displays, so we have to catch this event */
00175 
00176     XSync (instance->display, False);
00177     XSetErrorHandler (handle_error);
00178 
00179     instance->shminfo.readOnly = True;
00180     if (! (XShmAttach (instance->display, &(instance->shminfo))))
00181         shmerror = 1;
00182 
00183     XSync (instance->display, False);
00184     XSetErrorHandler (NULL);
00185     if (shmerror) {
00186     error:
00187         fprintf (stderr, "cannot create shared memory\n");
00188         return NULL;
00189     }
00190 
00191     return instance->shminfo.shmaddr;
00192 }
00193 
00194 static void destroy_shm (x11_instance_t * instance)
00195 {
00196     XShmDetach (instance->display, &(instance->shminfo));
00197     shmdt (instance->shminfo.shmaddr);
00198     shmctl (instance->shminfo.shmid, IPC_RMID, 0);
00199 }
00200 
00201 static void x11_event (x11_instance_t * instance)       /* XXXXXXXXXXX */
00202 {
00203     XEvent event;
00204     char * addr;
00205     int i;
00206 
00207     XNextEvent (instance->display, &event);
00208     if (event.type == instance->completion_type) {
00209         addr = (instance->shminfo.shmaddr +
00210                 ((XShmCompletionEvent *)&event)->offset);
00211         for (i = 0; i < 3; i++)
00212             if (addr == instance->frame[i].data)
00213                 instance->frame[i].wait_completion = 0;
00214     }
00215 }
00216 
00217 static void x11_start_fbuf (vo_instance_t * _instance,
00218                             uint8_t * const * buf, void * id)
00219 {
00220     x11_instance_t * instance = (x11_instance_t *) _instance;
00221     x11_frame_t * frame = (x11_frame_t *) id;
00222 
00223     while (frame->wait_completion)
00224         x11_event (instance);
00225 }
00226 
00227 static void x11_setup_fbuf (vo_instance_t * _instance,
00228                             uint8_t ** buf, void ** id)
00229 {
00230     x11_instance_t * instance = (x11_instance_t *) _instance;
00231 
00232     buf[0] = (uint8_t *) instance->frame[instance->index].data;
00233     buf[1] = buf[2] = NULL;
00234     *id = instance->frame + instance->index++;
00235 }
00236 
00237 static void x11_draw_frame (vo_instance_t * _instance,
00238                             uint8_t * const * buf, void * id)
00239 {
00240     x11_frame_t * frame;
00241     x11_instance_t * instance;
00242 
00243     frame = (x11_frame_t *) id;
00244     instance = (x11_instance_t *) _instance;
00245 
00246     XShmPutImage (instance->display, instance->window, instance->gc,
00247                   frame->ximage, 0, 0, 0, 0, instance->width, instance->height,
00248                   True);
00249     XFlush (instance->display);
00250     frame->wait_completion = 1;
00251 }
00252 
00253 static int x11_alloc_frames (x11_instance_t * instance)
00254 {
00255     int size;
00256     char * alloc;
00257     int i;
00258 
00259     size = 0;
00260     alloc = NULL;
00261     for (i = 0; i < 3; i++) {
00262         instance->frame[i].wait_completion = 0;
00263         instance->frame[i].ximage =
00264             XShmCreateImage (instance->display, instance->vinfo.visual,
00265                              instance->vinfo.depth, ZPixmap, NULL /* data */,
00266                              &(instance->shminfo),
00267                              instance->width, instance->height);
00268         if (instance->frame[i].ximage == NULL) {
00269             fprintf (stderr, "Cannot create ximage\n");
00270             return 1;
00271         } else if (i == 0) {
00272             size = (instance->frame[0].ximage->bytes_per_line *
00273                     instance->frame[0].ximage->height);
00274             alloc = (char *) create_shm (instance, 3 * size);
00275             if (alloc == NULL)
00276                 return 1;
00277         } else if (size != (instance->frame[0].ximage->bytes_per_line *
00278                             instance->frame[0].ximage->height)) {
00279             fprintf (stderr, "unexpected ximage data size\n");
00280             return 1;
00281         }
00282 
00283         instance->frame[i].data = instance->frame[i].ximage->data = alloc;
00284         alloc += size;
00285     }
00286     instance->index = 0;
00287     return 0;
00288 }
00289 
00290 static void x11_close (vo_instance_t * _instance)
00291 {
00292     x11_instance_t * instance = (x11_instance_t *) _instance;
00293     int i;
00294 
00295     for (i = 0; i < 3; i++) {
00296         while (instance->frame[i].wait_completion)
00297             x11_event (instance);
00298         XDestroyImage (instance->frame[i].ximage);
00299     }
00300     destroy_shm (instance);
00301     XFreeGC (instance->display, instance->gc);
00302     XDestroyWindow (instance->display, instance->window);
00303     XCloseDisplay (instance->display);
00304 }
00305 
00306 #ifdef LIBVO_XV
00307 static void xv_setup_fbuf (vo_instance_t * _instance,
00308                            uint8_t ** buf, void ** id)
00309 {
00310     x11_instance_t * instance = (x11_instance_t *) _instance;
00311     uint8_t * data;
00312 
00313     data = (uint8_t *) instance->frame[instance->index].xvimage->data;
00314     buf[0] = data + instance->frame[instance->index].xvimage->offsets[0];
00315     buf[1] = data + instance->frame[instance->index].xvimage->offsets[2];
00316     buf[2] = data + instance->frame[instance->index].xvimage->offsets[1];
00317     *id = instance->frame + instance->index++;
00318 }
00319 
00320 static void xv_draw_frame (vo_instance_t * _instance,
00321                            uint8_t * const * buf, void * id)
00322 {
00323     x11_frame_t * frame = (x11_frame_t *) id;
00324     x11_instance_t * instance = (x11_instance_t *) _instance;
00325 
00326     XvShmPutImage (instance->display, instance->port, instance->window,
00327                    instance->gc, frame->xvimage, 0, 0,
00328                    instance->width, instance->height, 0, 0,
00329                    instance->width, instance->height, True);
00330     XFlush (instance->display);
00331     frame->wait_completion = 1;
00332 }
00333 
00334 static int xv_check_yv12 (x11_instance_t * instance, XvPortID port)
00335 {
00336     XvImageFormatValues * formatValues;
00337     int formats;
00338     int i;
00339 
00340     formatValues = XvListImageFormats (instance->display, port, &formats);
00341     for (i = 0; i < formats; i++)
00342         if ((formatValues[i].id == FOURCC_YV12) &&
00343             (! (strcmp (formatValues[i].guid, "YV12")))) {
00344             XFree (formatValues);
00345             return 0;
00346         }
00347     XFree (formatValues);
00348     return 1;
00349 }
00350 
00351 static int xv_check_extension (x11_instance_t * instance)
00352 {
00353     unsigned int version;
00354     unsigned int release;
00355     unsigned int dummy;
00356     unsigned int adaptors;
00357     unsigned int i;
00358     unsigned long j;
00359     XvAdaptorInfo * adaptorInfo;
00360 
00361     if ((XvQueryExtension (instance->display, &version, &release,
00362                            &dummy, &dummy, &dummy) != Success) ||
00363         (version < 2) || ((version == 2) && (release < 2))) {
00364         fprintf (stderr, "No xv extension\n");
00365         return 1;
00366     }
00367 
00368     XvQueryAdaptors (instance->display, instance->window, &adaptors,
00369                      &adaptorInfo);
00370 
00371     for (i = 0; i < adaptors; i++)
00372         if (adaptorInfo[i].type & XvImageMask)
00373             for (j = 0; j < adaptorInfo[i].num_ports; j++)
00374                 if ((! (xv_check_yv12 (instance,
00375                                        adaptorInfo[i].base_id + j))) &&
00376                     (XvGrabPort (instance->display, adaptorInfo[i].base_id + j,
00377                                  0) == Success)) {
00378                     instance->port = adaptorInfo[i].base_id + j;
00379                     XvFreeAdaptorInfo (adaptorInfo);
00380                     return 0;
00381                 }
00382 
00383     XvFreeAdaptorInfo (adaptorInfo);
00384     fprintf (stderr, "Cannot find xv port\n");
00385     return 1;
00386 }
00387 
00388 static int xv_alloc_frames (x11_instance_t * instance)
00389 {
00390     int size;
00391     char * alloc;
00392     int i;
00393 
00394     size = instance->width * instance->height / 4;
00395     alloc = (char *) create_shm (instance, 18 * size);
00396     if (alloc == NULL)
00397         return 1;
00398 
00399     for (i = 0; i < 3; i++) {
00400         instance->frame[i].wait_completion = 0;
00401         instance->frame[i].xvimage =
00402             XvShmCreateImage (instance->display, instance->port, FOURCC_YV12,
00403                               alloc, instance->width, instance->height,
00404                               &(instance->shminfo));
00405         if ((instance->frame[i].xvimage == NULL) ||
00406             (instance->frame[i].xvimage->data_size != 6 * size)) { /* FIXME */
00407             fprintf (stderr, "Cannot create xvimage\n");
00408             return 1;
00409         }
00410         instance->frame[i].data = alloc;
00411         alloc += 6 * size;
00412     }
00413 
00414     return 0;
00415 }
00416 
00417 static void xv_close (vo_instance_t * _instance)
00418 {
00419     x11_instance_t * instance = (x11_instance_t *) _instance;
00420     int i;
00421 
00422     for (i = 0; i < 3; i++) {
00423         while (instance->frame[i].wait_completion)
00424             x11_event (instance);
00425         XFree (instance->frame[i].xvimage);
00426     }
00427     destroy_shm (instance);
00428     XvUngrabPort (instance->display, instance->port, 0);
00429     XFreeGC (instance->display, instance->gc);
00430     XDestroyWindow (instance->display, instance->window);
00431     XCloseDisplay (instance->display);
00432 }
00433 #endif
00434 
00435 static int common_setup (x11_instance_t * instance, int width, int height,
00436                          vo_setup_result_t * result, int xv)
00437 {
00438     instance->vo.set_fbuf = NULL;
00439     instance->vo.discard = NULL;
00440     instance->vo.start_fbuf = x11_start_fbuf;
00441     instance->width = width;
00442     instance->height = height;
00443 
00444     if (open_display (instance))
00445         return 1;
00446 
00447 #ifdef LIBVO_XV
00448     if (xv && (! (xv_check_extension (instance)))) {
00449         if (xv_alloc_frames (instance))
00450             return 1;
00451         instance->vo.setup_fbuf = xv_setup_fbuf;
00452         instance->vo.draw = xv_draw_frame;
00453         instance->vo.close = xv_close;
00454         result->convert = NULL;
00455     } else
00456 #endif
00457     {
00458         if (x11_alloc_frames (instance))
00459             return 1;
00460         instance->vo.setup_fbuf = x11_setup_fbuf;
00461         instance->vo.draw = x11_draw_frame;
00462         instance->vo.close = x11_close;
00463 
00464 #ifdef WORDS_BIGENDIAN
00465         if (instance->frame[0].ximage->byte_order != MSBFirst) {
00466             fprintf (stderr, "No support for non-native byte order\n");
00467             return 1;
00468         }
00469 #else
00470         if (instance->frame[0].ximage->byte_order != LSBFirst) {
00471             fprintf (stderr, "No support for non-native byte order\n");
00472             return 1;
00473         }
00474 #endif
00475 
00476         /*
00477          * depth in X11 terminology land is the number of bits used to
00478          * actually represent the colour.
00479          *
00480          * bpp in X11 land means how many bits in the frame buffer per
00481          * pixel.
00482          *
00483          * ex. 15 bit color is 15 bit depth and 16 bpp. Also 24 bit
00484          *     color is 24 bit depth, but can be 24 bpp or 32 bpp.
00485          *
00486          * If we have blue in the lowest bit then "obviously" RGB
00487          * (the guy who wrote this convention never heard of endianness ?)
00488          */
00489 
00490         result->convert =
00491             convert_rgb (((instance->frame[0].ximage->blue_mask & 1) ?
00492                           CONVERT_RGB : CONVERT_BGR),
00493                          ((instance->vinfo.depth == 24) ?
00494                           instance->frame[0].ximage->bits_per_pixel :
00495                           instance->vinfo.depth));
00496     }
00497 
00498     XMapWindow (instance->display, instance->window);
00499 
00500     return 0;
00501 }
00502 
00503 static int x11_setup (vo_instance_t * instance, int width, int height,
00504                       vo_setup_result_t * result)
00505 {
00506     return common_setup ((x11_instance_t *)instance, width, height, result, 0);
00507 }
00508 
00509 vo_instance_t * vo_x11_open (void)
00510 {
00511     x11_instance_t * instance;
00512 
00513     instance = (x11_instance_t *) malloc (sizeof (x11_instance_t));
00514     if (instance == NULL)
00515         return NULL;
00516 
00517     instance->vo.setup = x11_setup;
00518     return (vo_instance_t *) instance;
00519 }
00520 
00521 #ifdef LIBVO_XV
00522 static int xv_setup (vo_instance_t * instance, int width, int height,
00523                      vo_setup_result_t * result)
00524 {
00525     return common_setup ((x11_instance_t *)instance, width, height, result, 1);
00526 }
00527 
00528 vo_instance_t * vo_xv_open (void)
00529 {
00530     x11_instance_t * instance;
00531 
00532     instance = (x11_instance_t *) malloc (sizeof (x11_instance_t));
00533     if (instance == NULL)
00534         return NULL;
00535 
00536     instance->vo.setup = xv_setup;
00537     return (vo_instance_t *) instance;
00538 }
00539 #endif
00540 #endif
 

Powered by Plone

This site conforms to the following standards: